257 lines
5.7 KiB
C++
257 lines
5.7 KiB
C++
#pragma once
|
|
|
|
|
|
#include "../common/adc_traits.h"
|
|
|
|
namespace adc
|
|
{
|
|
|
|
|
|
/*
|
|
* Very simple URL parser and holder class
|
|
*
|
|
* URL: proto_mark://host_name:port_num/path
|
|
*/
|
|
|
|
class AdcURL
|
|
{
|
|
protected:
|
|
static constexpr std::string_view protoHostDelim = "://";
|
|
static constexpr std::string_view hostPortDelim = ":";
|
|
static constexpr std::string_view portPathDelim = "/";
|
|
|
|
public:
|
|
enum proto_id_t { PROTO_ID_LOCAL, PROTO_ID_TCP, PROTO_ID_TLS, PROTO_ID_UDP, PROTO_ID_WS, PROTO_ID_WSS };
|
|
|
|
static constexpr std::string_view protoMarkLocal{"local"}; // UNIX domain
|
|
static constexpr std::string_view protoMarkTCP{"tcp"}; // TCP
|
|
static constexpr std::string_view protoMarkTLS{"tls"}; // TLS
|
|
static constexpr std::string_view protoMarkUDP{"udp"}; // UDP
|
|
static constexpr std::string_view protoMarkWS{"ws"}; // Websocket
|
|
static constexpr std::string_view protoMarkWSS{"wss"}; // Secure Websocket
|
|
|
|
static constexpr std::array validProtoMarks = {protoMarkLocal, protoMarkTCP, protoMarkTLS,
|
|
protoMarkUDP, protoMarkWS, protoMarkWSS};
|
|
|
|
/* Constructors and destructor */
|
|
|
|
AdcURL() = default;
|
|
|
|
// full-feature constructor
|
|
template <traits::adc_input_char_range HT, traits::adc_input_char_range PTT>
|
|
AdcURL(proto_id_t proto_id, HT&& host, int port, PTT&& path) : AdcURL()
|
|
{
|
|
setURL(proto_id, std::forward<HT>(host), port, std::forward<PTT>(path));
|
|
}
|
|
|
|
|
|
bool valid() const
|
|
{
|
|
//
|
|
return _isValid;
|
|
}
|
|
|
|
|
|
template <traits::adc_output_char_range R>
|
|
R url() const
|
|
{
|
|
R r;
|
|
if (!_isValid) {
|
|
return r;
|
|
}
|
|
|
|
if (_protoID == PROTO_ID_LOCAL) { // only proto mark, host and its delimiter
|
|
std::ranges::copy(_urlView | std::views::take(3) | std::views::join, std::back_inserter(r));
|
|
} else {
|
|
std::ranges::copy(_urlView | std::views::join, std::back_inserter(r));
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
std::string url() const
|
|
{
|
|
//
|
|
return url<std::string>();
|
|
}
|
|
|
|
|
|
template <traits::adc_char_view R>
|
|
R proto() const
|
|
{
|
|
if (!_isValid) {
|
|
return R();
|
|
}
|
|
|
|
const auto& proto = validProtoMarks[_protoID];
|
|
return R{proto.begin(), proto.end()};
|
|
}
|
|
|
|
|
|
std::string_view proto() const
|
|
{
|
|
if (!_isValid) {
|
|
return std::string_view();
|
|
}
|
|
|
|
return validProtoMarks[_protoID];
|
|
}
|
|
|
|
|
|
template <traits::adc_output_char_range R>
|
|
R host() const
|
|
{
|
|
R r;
|
|
if (!_isValid) {
|
|
return r;
|
|
}
|
|
|
|
std::ranges::copy(_host, std::back_inserter(r));
|
|
|
|
return r;
|
|
}
|
|
|
|
template <traits::adc_char_view R>
|
|
R hostView() const
|
|
{
|
|
if (!_isValid) {
|
|
return R();
|
|
}
|
|
|
|
return R{_host.begin(), _host.end()};
|
|
}
|
|
|
|
std::string host() const
|
|
{
|
|
//
|
|
return _host;
|
|
}
|
|
|
|
std::string_view hostView() const
|
|
{
|
|
//
|
|
return std::string_view{_host.begin(), _host.end()};
|
|
}
|
|
|
|
|
|
int port() const
|
|
{
|
|
//
|
|
return _isValid ? _port : -1;
|
|
}
|
|
|
|
template <traits::adc_output_char_range R>
|
|
R path() const
|
|
{
|
|
R r;
|
|
if (!_isValid) {
|
|
return r;
|
|
}
|
|
|
|
std::ranges::copy(_path, std::back_inserter(r));
|
|
|
|
return r;
|
|
}
|
|
|
|
template <traits::adc_char_view R>
|
|
R pathView() const
|
|
{
|
|
if (!_isValid) {
|
|
return R();
|
|
}
|
|
|
|
return R{_path.begin(), _path.end()};
|
|
}
|
|
|
|
std::string path() const
|
|
{
|
|
//
|
|
return _isValid ? _path : "";
|
|
}
|
|
|
|
std::string_view pathView() const
|
|
{
|
|
//
|
|
return _isValid ? std::string_view{_path.begin(), _path.end()} : std::string_view();
|
|
}
|
|
|
|
template <traits::adc_input_char_range HT, traits::adc_input_char_range PTT>
|
|
bool setURL(proto_id_t proto_id, HT&& host, int port, PTT&& path)
|
|
{
|
|
if (!std::distance(host.begin(), host.end())) {
|
|
return false;
|
|
}
|
|
|
|
switch (proto_id) {
|
|
case PROTO_ID_LOCAL:
|
|
// ignore path (always "") and port (just skip)
|
|
_port = -1;
|
|
_path.clear();
|
|
|
|
break;
|
|
case PROTO_ID_TCP:
|
|
case PROTO_ID_TLS:
|
|
case PROTO_ID_UDP:
|
|
case PROTO_ID_WS:
|
|
case PROTO_ID_WSS:
|
|
if (port <= 0) {
|
|
return false;
|
|
}
|
|
|
|
_port = port;
|
|
|
|
_path.clear();
|
|
std::ranges::copy(std::forward<PTT>(path), std::back_inserter(_path));
|
|
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
_isValid = true;
|
|
|
|
_protoID = proto_id;
|
|
|
|
_host.clear();
|
|
std::ranges::copy(std::forward<PTT>(host), std::back_inserter(_host));
|
|
|
|
updateURLView();
|
|
|
|
return true;
|
|
}
|
|
|
|
template <traits::adc_input_char_range R>
|
|
bool setURL(R&& r)
|
|
{
|
|
auto found = std::ranges::search(std::forward<R>(r), protoHostDelim);
|
|
|
|
if (found.empty()) {
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
}
|
|
|
|
protected:
|
|
bool _isValid{false};
|
|
proto_id_t _protoID;
|
|
std::string _host, _path, _portStr;
|
|
int _port;
|
|
|
|
std::array<std::string_view, 7> _urlView{protoMarkLocal, protoHostDelim, "localhost", hostPortDelim,
|
|
"7777", portPathDelim, ""};
|
|
|
|
void updateURLView()
|
|
{
|
|
_urlView[0] = validProtoMarks[_protoID];
|
|
_urlView[2] = _host.c_str();
|
|
_portStr = std::to_string(_port);
|
|
_urlView[4] = _port == -1 ? "" : _portStr.c_str();
|
|
_urlView[6] = _path.c_str();
|
|
}
|
|
};
|
|
|
|
} // namespace adc
|