From cf67072bed0e77bf3f7f5a5beef480af0d0f0566 Mon Sep 17 00:00:00 2001 From: peri4 Date: Tue, 26 May 2026 21:38:00 +0300 Subject: [PATCH] add files --- libs/main/http_common/piserverendpoint.cpp | 125 +++++++++++++++++++++ libs/main/http_common/piserverendpoint_p.h | 72 ++++++++++++ 2 files changed, 197 insertions(+) create mode 100644 libs/main/http_common/piserverendpoint.cpp create mode 100644 libs/main/http_common/piserverendpoint_p.h diff --git a/libs/main/http_common/piserverendpoint.cpp b/libs/main/http_common/piserverendpoint.cpp new file mode 100644 index 00000000..cfcd253a --- /dev/null +++ b/libs/main/http_common/piserverendpoint.cpp @@ -0,0 +1,125 @@ +#include "piliterals_string.h" +#include "piserverendpoint_p.h" + + +PIStringList PIHTTP::ServerEndpoint::splitPath(const PIString & path) { + auto ret = path.split("/"); + ret.removeAll({}); + return ret; +} + + +PIHTTP::ServerEndpoint::PathElement::PathElement(const PIString & reg) { + source = reg; + if (reg == "*"_a) { + type = Type::AnyOne; + } else if (reg == "**"_a) { + type = Type::AnyMany; + } else if (reg.contains('*')) { + type = Type::AnyPart; + parts = reg.split('*'); + } else if (reg.contains('{')) { + type = Type::Arguments; + int ind = 0, eind = 0, pind = 0; + for (;;) { + ind = reg.find('{', ind); + if (ind < 0) break; + eind = reg.find('}', ind + 1); + if (eind < 0) break; + arguments.insert(arguments.size_s(), reg.mid(ind + 1, eind - ind - 1)); + if (ind == 0) + parts << PIString(); + else { + if (ind > pind) + parts << reg.mid(pind, ind - pind); + else if (parts.isNotEmpty()) { + piCout << "[PIHTTP::ServerEndpoint] Warning: sequential arguments, ignoring this path!"; + type = Type::Invalid; + return; + } + } + ind = pind = eind + 1; + } + if (eind < reg.size_s() - 1) parts << reg.mid(eind + 1); + } +} + + +bool PIHTTP::ServerEndpoint::PathElement::match(const PIString & in, PIMap & ext_args) const { + // piCout << "match" << source << "with" << in; + if (type == Type::AnyOne) return true; + if (type == Type::AnyPart) { + int ind = 0; + for (const auto & m: parts) { + ind = in.find(m, ind); + if (ind < 0) return false; + } + return true; + } + if (type == Type::Arguments) { + int ind = 0, eind = 0; + for (int i = 0; i < parts.size_s(); ++i) { + const auto & m(parts[i]); + if (m.isNotEmpty()) { + ind = in.find(m, eind); + if (ind < 0) return false; + } + if (i > 0) { + ext_args[arguments.value(i - 1)] = in.mid(eind, ind - eind); + } + eind = ind + m.size_s(); + } + if (parts.size() == arguments.size()) { + ext_args[arguments.value(arguments.size_s() - 1)] = in.mid(eind); + } + return true; + } + return source == in; +} + + +uint PIHTTP::ServerEndpoint::PathElement::priority() const { + switch (type) { + case Type::Fixed: return 0x10000; break; + case Type::Arguments: return 0x1000; break; + case Type::AnyPart: return 0x100; break; + case Type::AnyOne: return 0x10; break; + case Type::AnyMany: return 0x1; break; + default: break; + } + return 0; +} + + +bool PIHTTP::ServerEndpoint::create(const PIString & p) { + path = splitPath(p); + prepared_path.clear(); + priority = 0; + for (const auto & i: path) { + PathElement pe(i); + prepared_path << pe; + path_types |= pe.type; + priority += pe.priority(); + } + return !path_types[PathElement::Type::Invalid]; +} + + +bool PIHTTP::ServerEndpoint::match(const PIStringList & in_path, PIMap & ext_args) const { + if (path_types[PathElement::Type::AnyMany]) { + int any_ind = path.indexOf("**"_a); + for (int i = 0; i < any_ind; ++i) { + if (!prepared_path[i].match(in_path[i], ext_args)) return false; + } + int si = prepared_path.size_s() - 1, ii = in_path.size_s() - 1; + for (; si > any_ind && ii >= 0; --si, --ii) { + if (!prepared_path[si].match(in_path[ii], ext_args)) return false; + } + } else { + if (in_path.size() != prepared_path.size()) return false; + for (int i = 0; i < prepared_path.size_s(); ++i) { + if (!prepared_path[i].match(in_path[i], ext_args)) return false; + } + } + return true; +} diff --git a/libs/main/http_common/piserverendpoint_p.h b/libs/main/http_common/piserverendpoint_p.h new file mode 100644 index 00000000..22e4a181 --- /dev/null +++ b/libs/main/http_common/piserverendpoint_p.h @@ -0,0 +1,72 @@ +//! \~\file piserverendpoint_p.h +//! \~\ingroup HTTP +//! \~\brief +//! \~english Shared HTTP message container types +//! \~russian Общие типы контейнеров HTTP-сообщений +/* + PIP - Platform Independent Primitives + Shared HTTP message container types + Ivan Pelipenko peri4ko@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#ifndef piserverendpoint_p_h +#define piserverendpoint_p_h + +#include "pip_export.h" +#include "pistringlist.h" + + +namespace PIHTTP { + + +struct PIP_EXPORT ServerEndpoint { + struct PIP_EXPORT PathElement { + enum class Type { + Invalid = 0x01, + Fixed = 0x02, + Arguments = 0x04, + AnyOne = 0x08, + AnyPart = 0x10, + AnyMany = 0x20 + }; + + Type type = Type::Fixed; + PIString source; + PIStringList parts; + PIMap arguments; + + PathElement(const PIString & reg = {}); + + bool match(const PIString & in, PIMap & ext_args) const; + uint priority() const; + }; + + PIStringList path; + PIFlags path_types; + PIVector prepared_path; + uint priority = 0; + + bool create(const PIString & p); + bool match(const PIStringList & in_path, PIMap & ext_args) const; + + static PIStringList splitPath(const PIString & path); +}; + + +}; // namespace PIHTTP + + +#endif