фикс ошибок релизной сборки и парсинга большого тела запроса

This commit is contained in:
Vladislav Ostapov 2024-11-13 11:25:48 +03:00
parent 90b1f221ea
commit 8da8c054bf
7 changed files with 66 additions and 27 deletions

View File

@ -14,7 +14,7 @@ include(CheckCXXCompilerFlag)
set(CMAKE_CXX_FLAGS -fPIC) set(CMAKE_CXX_FLAGS -fPIC)
set(default_build_type "Release") set(default_build_type "Release")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
set(CMAKE_CXX_FLAGS_DEBUG "-ggdb -O0 -fprofile-arcs -ftest-coverage") set(CMAKE_CXX_FLAGS_DEBUG "-ggdb -O0 -fprofile-arcs -ftest-coverage")
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -s -DNDEBUG ") set(CMAKE_CXX_FLAGS_RELEASE "-O2 -s -DNDEBUG ")
message(${CMAKE_CXX_FLAGS}) message(${CMAKE_CXX_FLAGS})

View File

@ -98,9 +98,9 @@ namespace http::auth {
~AuthRequiredResource() override; ~AuthRequiredResource() override;
private: private:
uint32_t perms;
resource::respGenerator generator_;
AuthProvider& provider_; AuthProvider& provider_;
resource::respGenerator generator_;
uint32_t perms;
}; };
} }

View File

@ -13,6 +13,8 @@ namespace http::server {
} }
void Connection::start() { void Connection::start() {
request_parser_.reset();
request_.reset();
doRead(); doRead();
} }
@ -23,9 +25,6 @@ namespace http::server {
Connection::~Connection() = default; Connection::~Connection() = default;
void Connection::doRead() { void Connection::doRead() {
request_parser_.reset();
request_.reset();
auto self(shared_from_this()); auto self(shared_from_this());
socket_.async_read_some(boost::asio::buffer(buffer_), [this, self](boost::system::error_code ec, std::size_t bytes_transferred) { socket_.async_read_some(boost::asio::buffer(buffer_), [this, self](boost::system::error_code ec, std::size_t bytes_transferred) {
if (!ec) { if (!ec) {
@ -38,6 +37,7 @@ namespace http::server {
doWrite(); doWrite();
} else if (result == RequestParser::bad) { } else if (result == RequestParser::bad) {
stockReply(bad_request, reply_); stockReply(bad_request, reply_);
needClose = true;
doWrite(); doWrite();
} else { } else {
doRead(); doRead();
@ -59,7 +59,7 @@ namespace http::server {
auto self(shared_from_this()); auto self(shared_from_this());
async_write(socket_, reply_.to_buffers(), [this, self](boost::system::error_code ec, std::size_t) { async_write(socket_, reply_.to_buffers(), [this, self](boost::system::error_code ec, std::size_t) {
if (!ec) { if (!ec && !needClose) {
// keep alive Connection // keep alive Connection
doRead(); doRead();
} else { } else {
@ -74,6 +74,8 @@ namespace http::server {
void SslConnection::start() { void SslConnection::start() {
get_lowest_layer(stream_).expires_after(std::chrono::seconds(30)); get_lowest_layer(stream_).expires_after(std::chrono::seconds(30));
request_parser_.reset();
request_.reset();
// Perform the SSL handshake // Perform the SSL handshake
stream_.async_handshake(boost::asio::ssl::stream_base::server, boost::beast::bind_front_handler([this](auto ec) { stream_.async_handshake(boost::asio::ssl::stream_base::server, boost::beast::bind_front_handler([this](auto ec) {
@ -83,6 +85,7 @@ namespace http::server {
} }
void SslConnection::stop() { void SslConnection::stop() {
stream_.shutdown();
} }
SslConnection::~SslConnection() = default; SslConnection::~SslConnection() = default;
@ -90,9 +93,6 @@ namespace http::server {
void SslConnection::doRead() { void SslConnection::doRead() {
get_lowest_layer(stream_).expires_after(std::chrono::seconds(30)); get_lowest_layer(stream_).expires_after(std::chrono::seconds(30));
request_parser_.reset();
request_.reset();
auto self(shared_from_this()); auto self(shared_from_this());
stream_.async_read_some(boost::asio::buffer(buffer_), [this, self](boost::system::error_code ec, std::size_t bytes_transferred) { stream_.async_read_some(boost::asio::buffer(buffer_), [this, self](boost::system::error_code ec, std::size_t bytes_transferred) {
if (!ec) { if (!ec) {
@ -105,6 +105,7 @@ namespace http::server {
doWrite(); doWrite();
} else if (result == RequestParser::bad) { } else if (result == RequestParser::bad) {
stockReply(bad_request, reply_); stockReply(bad_request, reply_);
needClose = true;
doWrite(); doWrite();
} else { } else {
doRead(); doRead();
@ -126,8 +127,10 @@ namespace http::server {
auto self(shared_from_this()); auto self(shared_from_this());
async_write(stream_, reply_.to_buffers(), [this, self](boost::system::error_code ec, std::size_t) { async_write(stream_, reply_.to_buffers(), [this, self](boost::system::error_code ec, std::size_t) {
if (!ec) { if (!ec && !needClose) {
// keep alive Connection // keep alive Connection
request_parser_.reset();
request_.reset();
doRead(); doRead();
} else { } else {
connection_manager_.stop(shared_from_this()); connection_manager_.stop(shared_from_this());

View File

@ -72,6 +72,8 @@ namespace http::server {
/// The reply to be sent back to the client. /// The reply to be sent back to the client.
Reply reply_; Reply reply_;
bool needClose = false;
}; };
class SslConnection final : public ConnectionBase, public std::enable_shared_from_this<SslConnection> { class SslConnection final : public ConnectionBase, public std::enable_shared_from_this<SslConnection> {
@ -114,6 +116,8 @@ namespace http::server {
/// The reply to be sent back to the client. /// The reply to be sent back to the client.
Reply reply_; Reply reply_;
bool needClose = false;
}; };
typedef std::shared_ptr<ConnectionBase> connection_ptr; typedef std::shared_ptr<ConnectionBase> connection_ptr;

View File

@ -1,11 +1,31 @@
#include "request_parser.hpp" #include "request_parser.hpp"
#include <iostream>
#include <sstream> #include <sstream>
#include "request.hpp" #include "request.hpp"
namespace http::server { namespace http::server {
constexpr int HTTP_MAX_HEADERS = 64;
/**
* Функция, позволяющая или запрещающая выделение размера тела для запросов.
* @return true, если тело удовлетворяет размерам
*/
static bool requestBodySizeResolver(Request& req, size_t reqSize) {
// разрешаем тело только для POST запросов
if (req.method != "POST") {
return false;
}
// для обновления прошивки разрешаем большое тело
if (req.url->path == "/api/firmwareUpdate") {
return reqSize <= HTTP_MAX_PAYLOAD;
}
return reqSize < 0x4000; // 16кб на все POST-запросы к API будет более чем достаточно
}
static void parseParams(Url& u, const std::string& query) { static void parseParams(Url& u, const std::string& query) {
std::istringstream iss(query); std::istringstream iss(query);
std::string param; std::string param;
@ -72,7 +92,7 @@ namespace http::server {
switch (state_) { switch (state_) {
case expecting_payload: case expecting_payload:
req.payload.push_back(input); req.payload.push_back(input);
if (req.payload.size() <= contentLenghtHeader - 1) { if (req.payload.size() < contentLenghtHeader) {
return indeterminate; return indeterminate;
} }
return good; return good;
@ -186,17 +206,23 @@ namespace http::server {
if (input == '\r') { if (input == '\r') {
state_ = expecting_newline_3; state_ = expecting_newline_3;
return indeterminate; return indeterminate;
} else if (!req.headers.empty() && (input == ' ' || input == '\t')) { }
if (!req.headers.empty() && (input == ' ' || input == '\t')) {
state_ = header_lws; state_ = header_lws;
return indeterminate; return indeterminate;
} else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { }
if (!is_char(input) || is_ctl(input) || is_tspecial(input)) {
return bad; return bad;
} else { }
if (req.headers.size() > HTTP_MAX_HEADERS) {
return bad;
}
req.headers.emplace_back(); req.headers.emplace_back();
req.headers.back().name.push_back(input); req.headers.back().name.push_back(input);
state_ = header_name; state_ = header_name;
return indeterminate; return indeterminate;
}
case header_lws: case header_lws:
if (input == '\r') { if (input == '\r') {
state_ = expecting_newline_2; state_ = expecting_newline_2;
@ -255,12 +281,11 @@ namespace http::server {
if (contentLenghtHeader == 0) { if (contentLenghtHeader == 0) {
return good; return good;
} }
if (requestBodySizeResolver(req, contentLenghtHeader)) {
state_ = expecting_payload; state_ = expecting_payload;
if (contentLenghtHeader > HTTP_MAX_PAYLOAD) {
return bad;
}
return indeterminate; return indeterminate;
} }
}
return bad; return bad;
default: default:

View File

@ -25,12 +25,17 @@ static void loadFile(const std::string& path, std::vector<char>& content) {
http::resource::BasicResource::BasicResource(std::string path): path(std::move(path)) {} http::resource::BasicResource::BasicResource(std::string path): path(std::move(path)) {}
http::resource::StaticFileFactory::StaticFileDef::StaticFileDef(std::string path, server::mime_types::Mime type, bool allowCache): path(std::move(path)), type(type), allowCache(allowCache) { http::resource::StaticFileFactory::StaticFileDef::StaticFileDef(std::string path, server::mime_types::Mime type, bool allowCache): path(std::move(path)), type(type), allowCache(allowCache) {
#ifdef USE_DEBUG
if (allowCache) { if (allowCache) {
BOOST_LOG_TRIVIAL(info) << "Load static file " << this->path; BOOST_LOG_TRIVIAL(info) << "Load static file " << this->path;
loadFile(this->path, this->content); loadFile(this->path, this->content);
} else { } else {
BOOST_LOG_TRIVIAL(info) << "Skip loading static file " << this->path; BOOST_LOG_TRIVIAL(info) << "Skip loading static file " << this->path;
} }
#else
BOOST_LOG_TRIVIAL(info) << "Load static file " << this->path;
loadFile(this->path, this->content);
#endif
} }
http::resource::StaticFileFactory::StaticFileDef::~StaticFileDef() = default; http::resource::StaticFileFactory::StaticFileDef::~StaticFileDef() = default;

View File

@ -505,17 +505,19 @@ std::string api_driver::ApiDriver::loadSettings() const {
result << ",\n\"buc.refClk10M\":" << boolAsStr(bucLnb.is_ref_10MHz_buc); result << ",\n\"buc.refClk10M\":" << boolAsStr(bucLnb.is_ref_10MHz_buc);
switch (bucLnb.buc) { switch (bucLnb.buc) {
case voltage_buc::DISABLE: result << ",\"buc.powering\":0"; break;
case voltage_buc::_24V: result << ",\"buc.powering\":24"; break; case voltage_buc::_24V: result << ",\"buc.powering\":24"; break;
case voltage_buc::_48V: result << ",\"buc.powering\":48"; break; case voltage_buc::_48V: result << ",\"buc.powering\":48"; break;
case voltage_buc::DISABLE:
default: result << ",\"buc.powering\":0";
} }
result << ",\n\"lnb.refClk10M\":" << boolAsStr(bucLnb.is_ref_10MHz_lnb); result << ",\n\"lnb.refClk10M\":" << boolAsStr(bucLnb.is_ref_10MHz_lnb);
switch (bucLnb.lnb) { switch (bucLnb.lnb) {
case voltage_lnb::DISABLE: result << ",\"lnb.powering\":0"; break;
case voltage_lnb::_13V: result << ",\"lnb.powering\":13"; break; case voltage_lnb::_13V: result << ",\"lnb.powering\":13"; break;
case voltage_lnb::_18V: result << ",\"lnb.powering\":18"; break; case voltage_lnb::_18V: result << ",\"lnb.powering\":18"; break;
case voltage_lnb::_24V: result << ",\"lnb.powering\":24"; break; case voltage_lnb::_24V: result << ",\"lnb.powering\":24"; break;
case voltage_lnb::DISABLE:
default: result << ",\"lnb.powering\":0";
} }
result << ",\n\"serviceSettings.refClk10M\":" << boolAsStr(bucLnb.is_ref_10MHz_output); result << ",\n\"serviceSettings.refClk10M\":" << boolAsStr(bucLnb.is_ref_10MHz_output);