Kylin/HttpProxy/TemplateSegmentRule.cpp
2023-12-30 00:03:40 +08:00

97 lines
3.6 KiB
C++

#include "TemplateSegmentRule.h"
#include "BoostLog.h"
#include <boost/url/decode_view.hpp>
#include <boost/url/detail/replacement_field_rule.hpp>
#include <boost/url/error.hpp>
#include <boost/url/grammar.hpp>
#include <boost/url/rfc/detail/path_rules.hpp>
#include <string_view>
boost::urls::result<TemplateSegmentRule::value_type> TemplateSegmentRule::parse(const char *&iterator,
const char *end) const noexcept {
TemplateSegmentRule::value_type ret;
bool isTemplate = false;
if (iterator != end && *iterator == '{') {
auto it0 = iterator;
++iterator;
auto rightBraces = boost::urls::grammar::find_if(iterator, end, boost::urls::grammar::lut_chars('}'));
if (rightBraces != end) {
boost::core::string_view segment(iterator, rightBraces);
static constexpr auto modifiers_cs = boost::urls::grammar::lut_chars("?*+");
static constexpr auto id_rule = boost::urls::grammar::tuple_rule(
boost::urls::grammar::optional_rule(boost::urls::detail::arg_id_rule),
boost::urls::grammar::optional_rule(boost::urls::grammar::delim_rule(modifiers_cs)));
if (segment.empty() || boost::urls::grammar::parse(segment, id_rule)) {
isTemplate = true;
iterator = rightBraces + 1;
ret.m_string = boost::core::string_view(it0, rightBraces + 1);
ret.m_isLiteral = false;
if (segment.ends_with('?'))
ret.modifier = TemplateSegment::Modifier::Optional;
else if (segment.ends_with('*'))
ret.modifier = TemplateSegment::Modifier::Star;
else if (segment.ends_with('+'))
ret.modifier = TemplateSegment::Modifier::Plus;
}
}
if (!isTemplate) iterator = it0;
}
if (!isTemplate) {
auto rv = boost::urls::grammar::parse(iterator, end, boost::urls::detail::segment_rule);
BOOST_ASSERT(rv);
rv->decode({}, boost::urls::string_token::assign_to(ret.m_string));
ret.m_isLiteral = true;
}
return ret;
}
bool TemplateSegment::isLiteral() const {
return m_isLiteral;
}
bool TemplateSegment::isStar() const {
return modifier == Modifier::Star;
}
bool TemplateSegment::isPlus() const {
return modifier == Modifier::Plus;
}
bool TemplateSegment::isOptional() const {
return modifier == Modifier::Optional;
}
bool TemplateSegment::hasModifier() const {
return !m_isLiteral && modifier != Modifier::None;
}
boost::core::string_view TemplateSegment::id() const {
BOOST_ASSERT(!isLiteral());
boost::core::string_view r = {m_string};
r.remove_prefix(1);
r.remove_suffix(1);
if (r.ends_with('?') || r.ends_with('+') || r.ends_with('*')) r.remove_suffix(1);
return r;
}
boost::core::string_view TemplateSegment::string() const {
return m_string;
}
bool TemplateSegment::match(boost::urls::pct_string_view segement) const {
if (m_isLiteral) return *segement == m_string;
return true; // other nodes match any string
}
bool TemplateSegment::operator==(const TemplateSegment &other) const {
if (m_isLiteral != other.m_isLiteral) return false;
if (m_isLiteral) return m_string == other.m_string;
return modifier == other.modifier;
}
bool TemplateSegment::operator<(const TemplateSegment &other) const {
if (other.m_isLiteral) return false;
if (m_isLiteral) return !other.m_isLiteral;
return modifier < other.modifier;
}