This commit is contained in:
2024-10-21 18:11:35 +03:00
parent b8fdae9d16
commit 0d62c9defc
9 changed files with 247 additions and 68 deletions

View File

@@ -2,6 +2,9 @@
#include <algorithm>
#include "../common/adc_utils.h"
/*
ABSTRACT DEVICE COMPONENTS LIBRARY
@@ -19,13 +22,18 @@ namespace adc
* Very simple various protocols endpoint parser and holder class
*
* endpoint: proto_mark://host_name:port_num/path
* where "part" is optional for all protocol kinds;
* where "part" is optional for all non-local protocol kinds;
*
* for the "local" kind protocol the endpoint string must consists of
* only "proto_mark" and "host_name" fields
* (e.g.: local://APP_UNIX_SOCKET)
* for local kind of protocols the endpoint must be given as:
* local://stream/PATH
* local://datagram/PATH
* local://seqpacket/PATH
* where 'stream', 'datagram' and 'seqpacket' "host_name"-field marks the
* stream-type, datagram-type and seqpacket-type UNIX domain sockets protocols.
* here, possible "port_num" field is allowed but ignored.
*
* NOTE: "proto_mark" and "host_name" (for local kind) fields are parsed in case-insensitive manner!
*
* NOTE: "proto_mark" field is parsed as case-insensitive string!
*
*/
@@ -39,6 +47,7 @@ public:
enum proto_id_t : uint8_t {
PROTO_ID_LOCAL,
PROTO_ID_SEQLOCAL,
PROTO_ID_TCP,
PROTO_ID_TLS,
PROTO_ID_UDP,
@@ -58,6 +67,14 @@ public:
protoMarkUDP, protoMarkWS, protoMarkWSS};
static constexpr std::string_view localProtoTypeStream{"stream"}; // UNIX domain stream
static constexpr std::string_view localProtoTypeDatagram{"datagram"}; // UNIX domain datagram
static constexpr std::string_view localProtoTypeSeqpacket{"seqpacket"}; // UNIX domain seqpacket
static constexpr std::array validLocalProtoTypes{localProtoTypeStream, localProtoTypeDatagram,
localProtoTypeSeqpacket};
template <traits::adc_input_char_range R>
AdcEndpointParser(const R& ept)
{
@@ -81,7 +98,8 @@ public:
if constexpr (std::is_array_v<std::remove_cvref_t<R>>) {
_endpoint = ept;
} else {
std::ranges::copy(ept, _endpoint);
_endpoint.clear();
std::ranges::copy(ept, std::back_inserter(_endpoint));
}
auto found = std::ranges::search(_endpoint, protoHostDelim);
@@ -90,53 +108,59 @@ public:
}
_proto = std::string_view{_endpoint.begin(), found.begin()};
// for (auto& valid_proto : validProtoMarks) {
// _isValid = _proto == valid_proto;
// if (_isValid) {
// break;
// }
// }
// if (!_isValid) {
// return _isValid;
// }
// _isValid = false;
if (!checkProtoMark(_proto)) {
ssize_t idx;
if ((idx = checkProtoMark(std::string_view{_endpoint.begin(), found.begin()})) < 0) {
return _isValid;
}
_proto = validProtoMarks[idx];
_host = std::string_view{found.end(), _endpoint.end()};
if (_proto == protoMarkLocal) { // local proto allows only hostname
_path = std::string_view();
_port = -1;
auto f1 = std::ranges::search(_host, portPathDelim);
std::string_view port_sv;
if (f1.empty() && isLocal()) { // no path, but it is mandatory for 'local'!
return _isValid;
} else {
auto f1 = std::ranges::search(_host, hostPortDelim);
std::string_view port_sv;
if (f1.empty()) { // no port, but is must be!
_host = std::string_view(_host.begin(), f1.begin());
_path = std::string_view(f1.end(), &*_endpoint.end());
f1 = std::ranges::search(_host, hostPortDelim);
if (f1.empty() && !isLocal()) { // no port, but it is mandatory for non-local!
return _isValid;
} else {
}
port_sv = std::string_view(f1.end(), _host.end());
if (port_sv.size()) {
_host = std::string_view(_host.begin(), f1.begin());
// port_sv = std::string_view(f1.end(), _endpoint.end());
port_sv = std::string_view(f1.end(), &*_endpoint.end());
f1 = std::ranges::search(port_sv, portPathDelim);
if (f1.empty()) {
_path = std::string_view();
} else {
port_sv = std::string_view(port_sv.begin(), f1.begin());
if (!isLocal()) {
// convert port string to int
auto end_ptr = port_sv.data() + port_sv.size();
_path = std::string_view(f1.end(), &*_endpoint.end());
auto [ptr, ec] = std::from_chars(port_sv.data(), end_ptr, _port);
if (ec != std::errc() || ptr != end_ptr) {
return _isValid;
}
} else { // ignore for local
_port = -1;
}
} else {
_port = -1;
}
// convert port string to int
auto end_ptr = port_sv.data() + port_sv.size();
auto [ptr, ec] = std::from_chars(port_sv.data(), end_ptr, _port);
if (ec != std::errc() || ptr != end_ptr) {
if (isLocal()) { // check for special values
idx = 0;
if (std::ranges::any_of(validLocalProtoTypes, [&idx, this](const auto& el) {
bool ok = utils::AdcCharRangeCompare(_host, el, true);
if (!ok) {
++idx;
}
return ok;
})) {
_host = validLocalProtoTypes[idx];
} else {
return _isValid;
}
}
@@ -197,6 +221,22 @@ public:
return proto() == protoMarkLocal;
}
bool isLocalStream() const
{
return host() == localProtoTypeStream;
}
bool isLocalDatagram() const
{
return host() == localProtoTypeDatagram;
}
bool isLocalSeqpacket() const
{
return host() == localProtoTypeSeqpacket;
}
bool isTCP() const
{
return proto() == protoMarkTCP;
@@ -229,10 +269,22 @@ protected:
bool _isValid;
virtual bool checkProtoMark(std::string_view proto_mark)
virtual ssize_t checkProtoMark(std::string_view proto_mark)
{
return std::ranges::any_of(AdcEndpointParser::validProtoMarks,
[proto_mark](const auto& el) { return el == proto_mark; });
ssize_t idx = 0;
// case-insensitive look-up
bool found = std::ranges::any_of(AdcEndpointParser::validProtoMarks, [&idx, &proto_mark, this](const auto& el) {
bool ok = utils::AdcCharRangeCompare(proto_mark, el, true);
if (!ok) {
++idx;
}
return ok;
});
return found ? idx : -1;
}
enum EndpointPart { PROTO_PART, HOST_PART, PATH_PART };
@@ -242,9 +294,9 @@ protected:
{
R res;
if (!_isValid) {
return res;
}
// if (!_isValid) {
// return res;
// }
auto part = _proto;