Compare commits

..

3 Commits

8 changed files with 104 additions and 63 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,8 +59,10 @@ 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
request_parser_.reset();
request_.reset();
doRead(); doRead();
} else { } else {
connection_manager_.stop(shared_from_this()); connection_manager_.stop(shared_from_this());
@ -74,6 +76,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 +87,7 @@ namespace http::server {
} }
void SslConnection::stop() { void SslConnection::stop() {
stream_.shutdown();
} }
SslConnection::~SslConnection() = default; SslConnection::~SslConnection() = default;
@ -90,9 +95,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 +107,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 +129,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)) {
return bad;
} else {
req.headers.emplace_back();
req.headers.back().name.push_back(input);
state_ = header_name;
return indeterminate;
} }
if (!is_char(input) || is_ctl(input) || is_tspecial(input)) {
return bad;
}
if (req.headers.size() > HTTP_MAX_HEADERS) {
return bad;
}
req.headers.emplace_back();
req.headers.back().name.push_back(input);
state_ = header_name;
return indeterminate;
case header_lws: case header_lws:
if (input == '\r') { if (input == '\r') {
state_ = expecting_newline_2; state_ = expecting_newline_2;
@ -255,11 +281,10 @@ namespace http::server {
if (contentLenghtHeader == 0) { if (contentLenghtHeader == 0) {
return good; return good;
} }
state_ = expecting_payload; if (requestBodySizeResolver(req, contentLenghtHeader)) {
if (contentLenghtHeader > HTTP_MAX_PAYLOAD) { state_ = expecting_payload;
return bad; return indeterminate;
} }
return indeterminate;
} }
return bad; return bad;

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);

View File

@ -118,8 +118,8 @@
<label> <label>
<span>Режим работы</span> <span>Режим работы</span>
<select v-model="param.general.isCinC"> <select v-model="param.general.isCinC">
<option value="false">SCPC</option> <option :value="false">SCPC</option>
<option value="true">CinC</option> <option :value="true">CinC</option>
</select> </select>
</label> </label>
</div> </div>
@ -150,8 +150,8 @@
<label> <label>
<span>Входные данные</span> <span>Входные данные</span>
<select v-model="param.general.isTestInputData"> <select v-model="param.general.isTestInputData">
<option value="false">Ethernet</option> <option :value="false">Ethernet</option>
<option value="true">Тест (CW)</option> <option :value="true">Тест (CW)</option>
</select> </select>
</label> </label>
<h3>Параметры передачи</h3> <h3>Параметры передачи</h3>
@ -166,11 +166,11 @@
<label> <label>
<span>Roll-off</span> <span>Roll-off</span>
<select v-model="param.tx.rolloff"> <select v-model="param.tx.rolloff">
<option value="5">0.05</option> <option :value="5">0.05</option>
<option value="10">0.10</option> <option :value="10">0.10</option>
<option value="15">0.15</option> <option :value="15">0.15</option>
<option value="20">0.20</option> <option :value="20">0.20</option>
<option value="25">0.25</option> <option :value="25">0.25</option>
</select> </select>
</label> </label>
<label> <label>
@ -195,15 +195,15 @@
<label> <label>
<span>Размер кадра</span> <span>Размер кадра</span>
<select v-model="param.dvbs2.frameSizeNormal"> <select v-model="param.dvbs2.frameSizeNormal">
<option value="true">normal</option> <option :value="true">normal</option>
<option value="false">short</option> <option :value="false">short</option>
</select> </select>
</label> </label>
<!-- <label>--> <!-- <label>-->
<!-- <span>Пилот-символы</span>--> <!-- <span>Пилот-символы</span>-->
<!-- <select v-model="param.dvbs2.isPilots">--> <!-- <select v-model="param.dvbs2.isPilots">-->
<!-- <option value="true">pilots</option>--> <!-- <option :value="true">pilots</option>-->
<!-- <option value="false">no pilots</option>--> <!-- <option :value="false">no pilots</option>-->
<!-- </select>--> <!-- </select>-->
<!-- </label>--> <!-- </label>-->
@ -315,19 +315,19 @@
<label> <label>
<span>Roll-off</span> <span>Roll-off</span>
<select v-model="param.rx.rolloff"> <select v-model="param.rx.rolloff">
<option value="5">0.05</option> <option :value="5">0.05</option>
<option value="10">0.10</option> <option :value="10">0.10</option>
<option value="15">0.15</option> <option :value="15">0.15</option>
<option value="20">0.20</option> <option :value="20">0.20</option>
<option value="25">0.25</option> <option :value="25">0.25</option>
</select> </select>
</label> </label>
</div> </div>
</div> </div>
<button class="action-button" @click="settingsSubmitRxTx()">Сохранить <span class="submit-spinner" v-show="submitStatus.rxTx"></span></button> <button class="action-button" @click="settingsSubmitRxTx()">Сохранить <span class="submit-spinner" v-show="submitStatus.rxTx"></span></button>
<h2 v-show="param.general.isCinC">Настройки режима CinC</h2> <h2 v-show="param.general.isCinC === true">Настройки режима CinC</h2>
<div v-show="param.general.isCinC" class="settings-set-container"> <div v-show="param.general.isCinC === true" class="settings-set-container">
<label> <label>
<span>Метод расчета задержки</span> <span>Метод расчета задержки</span>
<select v-model="param.cinc.mode"> <select v-model="param.cinc.mode">
@ -517,7 +517,7 @@
</div> </div>
<div class="tabs-body-item" v-if="activeTab === 'admin'"> <div class="tabs-body-item" v-if="activeTab === 'admin'">
<p> <p>
Эти настройки пока недоступны, но скоро разработчик это поправит. А пока смотри на крокодила, или купи разработчику банку <strike>пива</strike> колы для ускорения процесса) Эти настройки пока недоступны, но скоро разработчик это поправит. А пока смотри на крокодила, или купи разработчику банку <span style="text-decoration: line-through;">пива</span> колы для ускорения процесса)
</p> </p>
<img loading="lazy" src="/images/krokodil_vzryvaetsya_hd.gif" alt="krokodil"> <img loading="lazy" src="/images/krokodil_vzryvaetsya_hd.gif" alt="krokodil">
<video preload="auto" controls style="max-width: 100%"> <video preload="auto" controls style="max-width: 100%">
@ -681,7 +681,7 @@
const app = new Vue({ const app = new Vue({
el: '#app', el: '#app',
data: { data: {
isCinC: null, isCinC: false,
// false - означает что статистика не отправляется, true - отправляется // false - означает что статистика не отправляется, true - отправляется
submitStatus: { submitStatus: {
@ -733,17 +733,17 @@
param: { param: {
general: { general: {
isCinC: false, isCinC: Boolean,
txEn: false, // включен/выключен txEn: Boolean, // включен/выключен
modulatorMode: 'normal', // режим работы модулятора modulatorMode: 'normal', // режим работы модулятора
autoStartTx: false, // было "режим работы передатчика" autoStartTx: Boolean, // было "режим работы передатчика"
isTestInputData: false, // входные данные: eth или test isTestInputData: Boolean, // входные данные: eth или test
}, },
tx: { tx: {
attenuation: null, // ослабление attenuation: Number, // ослабление
rolloff: null, rolloff: Number,
cymRate: null, cymRate: Number,
centerFreq: null, centerFreq: Number,
}, },
dvbs2: { dvbs2: {
mode: null, // ccm/acm mode: null, // ccm/acm
@ -948,12 +948,12 @@
let query = { let query = {
"cinc.mode": this.param.cinc.mode, "cinc.mode": this.param.cinc.mode,
"cinc.searchBandwidth": parseInt(this.param.cinc.searchBandwidth), "cinc.searchBandwidth": this.param.cinc.searchBandwidth,
"cinc.position.station.latitude": parseFloat(this.param.cinc.position.station.latitude), "cinc.position.station.latitude": this.param.cinc.position.station.latitude,
"cinc.position.station.longitude": parseFloat(this.param.cinc.position.station.longitude), "cinc.position.station.longitude": this.param.cinc.position.station.longitude,
"cinc.position.satelliteLongitude": parseFloat(this.param.cinc.position.satelliteLongitude), "cinc.position.satelliteLongitude": this.param.cinc.position.satelliteLongitude,
"cinc.delayMin": parseInt(this.param.cinc.delayMin), "cinc.delayMin": this.param.cinc.delayMin,
"cinc.delayMax": parseInt(this.param.cinc.delayMax) "cinc.delayMax": this.param.cinc.delayMax
} }
this.submitStatus.cinc = true this.submitStatus.cinc = true
fetch('/api/set/cinc', { fetch('/api/set/cinc', {