mirror of
https://github.com/matrix-construct/construct
synced 2025-03-14 05:20:17 +01:00
ircd::rfc3986: Reorg grammar stack; add variable valid() tool.
This commit is contained in:
parent
c5088c3af2
commit
46346f504e
2 changed files with 189 additions and 151 deletions
|
@ -26,23 +26,14 @@ namespace ircd::rfc3986
|
|||
constexpr size_t HOSTNAME_MAX {rfc1035::LABEL_MAX};
|
||||
constexpr size_t DOMAIN_MAX {rfc1035::NAME_MAX};
|
||||
|
||||
void valid_hostname(const string_view &); // name part
|
||||
bool valid_hostname(std::nothrow_t, const string_view &);
|
||||
void valid_literal(const string_view &); // ip4 | ip6
|
||||
bool valid_literal(std::nothrow_t, const string_view &);
|
||||
void valid_domain(const string_view &); // dot delimited hostnames
|
||||
bool valid_domain(std::nothrow_t, const string_view &);
|
||||
void valid_host(const string_view &); // domain | ip4 | ip6
|
||||
bool valid_host(std::nothrow_t, const string_view &);
|
||||
void valid_remote(const string_view &); // host + optional :port
|
||||
bool valid_remote(std::nothrow_t, const string_view &);
|
||||
|
||||
uint16_t port(const string_view &remote); // get portnum from valid remote
|
||||
string_view host(const string_view &remote); // get host without portnum
|
||||
|
||||
// urlencoding suite
|
||||
string_view encode(const mutable_buffer &, const string_view &url);
|
||||
string_view encode(const mutable_buffer &, const json::members &);
|
||||
string_view decode(const mutable_buffer &, const string_view &url);
|
||||
|
||||
// extractor suite
|
||||
uint16_t port(const string_view &remote); // get portnum from valid remote
|
||||
string_view host(const string_view &remote); // get host without portnum
|
||||
}
|
||||
|
||||
namespace ircd
|
||||
|
@ -58,19 +49,58 @@ struct ircd::rfc3986::parser
|
|||
template<class R = unused>
|
||||
using rule = boost::spirit::qi::rule<it, R, unused, unused, unused>;
|
||||
|
||||
// note in all examples that portnums are always optional
|
||||
static const rule<uint16_t> port;
|
||||
|
||||
static const rule<> ip4_octet;
|
||||
static const rule<> ip4_literal;
|
||||
static const rule<> ip4_address; // 1.2.3.4
|
||||
static const rule<> ip4_literal; // 1.2.3.4
|
||||
static const rule<> ip4_remote; // 1.2.3.4:12345
|
||||
|
||||
static const rule<> ip6_char;
|
||||
static const rule<> ip6_h16;
|
||||
static const rule<> ip6_piece;
|
||||
static const rule<> ip6_ipiece;
|
||||
static const rule<> ip6_ls32;
|
||||
static const rule<> ip6_addr[9];
|
||||
static const rule<> ip6_address;
|
||||
static const rule<> ip6_literal;
|
||||
static const rule<> hostname;
|
||||
static const rule<> domain;
|
||||
static const rule<> host;
|
||||
static const rule<> remote;
|
||||
static const rule<> ip6_address; // ::1
|
||||
static const rule<> ip6_literal; // [::1]
|
||||
static const rule<> ip6_remote; // [::1]:12345
|
||||
|
||||
static const rule<> ip_address; // 1.2.3.4 | ::1
|
||||
static const rule<> ip_literal; // 1.2.3.4 | [::1]
|
||||
static const rule<> ip_remote; // 1.2.3.4:12345 | [::1]:12345
|
||||
|
||||
static const rule<> hostname; // foo
|
||||
static const rule<> domain; // foo.com
|
||||
static const rule<> hostport; // foo.bar.com:12345
|
||||
|
||||
static const rule<> host; // 1.2.3.4 | ::1 | foo.com
|
||||
static const rule<> host_literal; // 1.2.3.4 | [::1] | foo.com
|
||||
|
||||
static const rule<> remote; // 1.2.3.4:12345 | [::1]:12345 | foo.com:12345
|
||||
};
|
||||
|
||||
// Validator suite
|
||||
namespace ircd::rfc3986
|
||||
{
|
||||
// Variable rule...
|
||||
void valid(const parser::rule<> &, const string_view &);
|
||||
bool valid(std::nothrow_t, const parser::rule<> &, const string_view &);
|
||||
|
||||
// convenience: parser::hostname
|
||||
void valid_hostname(const string_view &);
|
||||
bool valid_hostname(std::nothrow_t, const string_view &);
|
||||
|
||||
// convenience: parser::host
|
||||
void valid_host(const string_view &);
|
||||
bool valid_host(std::nothrow_t, const string_view &);
|
||||
|
||||
// convenience: parser::domainname
|
||||
void valid_domain(const string_view &);
|
||||
bool valid_domain(std::nothrow_t, const string_view &);
|
||||
|
||||
// convenience: parser::remote
|
||||
void valid_remote(const string_view &);
|
||||
bool valid_remote(std::nothrow_t, const string_view &);
|
||||
}
|
||||
|
|
268
ircd/rfc3986.cc
268
ircd/rfc3986.cc
|
@ -80,13 +80,27 @@ ircd::rfc3986::parser::ip4_octet
|
|||
,"IPv4 octet"
|
||||
};
|
||||
|
||||
decltype(ircd::rfc3986::parser::ip4_address)
|
||||
ircd::rfc3986::parser::ip4_address
|
||||
{
|
||||
repeat(3)[ip4_octet >> '.'] >> ip4_octet
|
||||
,"IPv4 address"
|
||||
};
|
||||
|
||||
decltype(ircd::rfc3986::parser::ip4_literal)
|
||||
ircd::rfc3986::parser::ip4_literal
|
||||
{
|
||||
repeat(3)[ip4_octet >> '.'] >> ip4_octet
|
||||
ip4_address
|
||||
,"IPv4 literal"
|
||||
};
|
||||
|
||||
decltype(ircd::rfc3986::parser::ip4_remote)
|
||||
ircd::rfc3986::parser::ip4_remote
|
||||
{
|
||||
ip4_literal >> -(':' > port)
|
||||
,"IPv4 remote"
|
||||
};
|
||||
|
||||
decltype(ircd::rfc3986::parser::ip6_char)
|
||||
ircd::rfc3986::parser::ip6_char
|
||||
{
|
||||
|
@ -120,7 +134,7 @@ ircd::rfc3986::parser::ip6_ipiece
|
|||
decltype(ircd::rfc3986::parser::ip6_ls32)
|
||||
ircd::rfc3986::parser::ip6_ls32
|
||||
{
|
||||
(ip6_h16 >> ':' >> ip6_h16) | ip4_literal
|
||||
(ip6_h16 >> ':' >> ip6_h16) | ip4_address
|
||||
};
|
||||
|
||||
/// https://tools.ietf.org/html/rfc3986 Appendix A
|
||||
|
@ -151,7 +165,35 @@ decltype(ircd::rfc3986::parser::ip6_literal)
|
|||
ircd::rfc3986::parser::ip6_literal
|
||||
{
|
||||
'[' >> ip6_address >> ']'
|
||||
,"ip6 literal"
|
||||
,"IPv6 literal"
|
||||
};
|
||||
|
||||
decltype(ircd::rfc3986::parser::ip6_remote)
|
||||
ircd::rfc3986::parser::ip6_remote
|
||||
{
|
||||
ip6_literal >> -(':' > port)
|
||||
,"IPv6 literal"
|
||||
};
|
||||
|
||||
decltype(ircd::rfc3986::parser::ip_address)
|
||||
ircd::rfc3986::parser::ip_address
|
||||
{
|
||||
ip6_address | ip4_address
|
||||
,"IP address"
|
||||
};
|
||||
|
||||
decltype(ircd::rfc3986::parser::ip_literal)
|
||||
ircd::rfc3986::parser::ip_literal
|
||||
{
|
||||
ip6_literal | ip4_literal
|
||||
,"IP literal"
|
||||
};
|
||||
|
||||
decltype(ircd::rfc3986::parser::ip_remote)
|
||||
ircd::rfc3986::parser::ip_remote
|
||||
{
|
||||
ip_literal >> -(':' > port)
|
||||
,"IP literal"
|
||||
};
|
||||
|
||||
decltype(ircd::rfc3986::parser::hostname)
|
||||
|
@ -168,17 +210,31 @@ ircd::rfc3986::parser::domain
|
|||
,"domain"
|
||||
};
|
||||
|
||||
decltype(ircd::rfc3986::parser::hostport)
|
||||
ircd::rfc3986::parser::hostport
|
||||
{
|
||||
domain >> -(':' > port)
|
||||
,"hostport"
|
||||
};
|
||||
|
||||
decltype(ircd::rfc3986::parser::host)
|
||||
ircd::rfc3986::parser::host
|
||||
{
|
||||
ip6_literal | ip4_literal | domain
|
||||
ip6_address | ip4_address | domain
|
||||
,"host"
|
||||
};
|
||||
|
||||
decltype(ircd::rfc3986::parser::host_literal)
|
||||
ircd::rfc3986::parser::host_literal
|
||||
{
|
||||
ip_literal | domain
|
||||
,"host literal"
|
||||
};
|
||||
|
||||
decltype(ircd::rfc3986::parser::remote)
|
||||
ircd::rfc3986::parser::remote
|
||||
{
|
||||
host >> -(':' > port)
|
||||
ip_remote | hostport
|
||||
,"remote"
|
||||
};
|
||||
|
||||
|
@ -269,9 +325,19 @@ ircd::string_view
|
|||
ircd::rfc3986::host(const string_view &str)
|
||||
try
|
||||
{
|
||||
static const parser::rule<string_view> literal
|
||||
{
|
||||
parser::ip6_address
|
||||
};
|
||||
|
||||
static const parser::rule<string_view> non_literal
|
||||
{
|
||||
parser::ip6_address | parser::ip4_address | parser::domain
|
||||
};
|
||||
|
||||
static const parser::rule<string_view> rule
|
||||
{
|
||||
raw[parser::host]
|
||||
(lit('[') >> raw[literal]) | raw[non_literal]
|
||||
,"host"
|
||||
};
|
||||
|
||||
|
@ -289,9 +355,19 @@ uint16_t
|
|||
ircd::rfc3986::port(const string_view &str)
|
||||
try
|
||||
{
|
||||
static const parser::rule<> literal
|
||||
{
|
||||
parser::ip6_literal | parser::ip4_literal | parser::domain
|
||||
};
|
||||
|
||||
static const parser::rule<> non_literal
|
||||
{
|
||||
parser::ip6_address
|
||||
};
|
||||
|
||||
static const parser::rule<uint16_t> rule
|
||||
{
|
||||
(eps > parser::host) >> -(lit(':') >> parser::port)
|
||||
non_literal | (literal >> -(lit(':') >> parser::port) >> eoi)
|
||||
,"port"
|
||||
};
|
||||
|
||||
|
@ -309,27 +385,15 @@ bool
|
|||
ircd::rfc3986::valid_remote(std::nothrow_t,
|
||||
const string_view &str)
|
||||
{
|
||||
static const auto &rule
|
||||
{
|
||||
parser::remote >> eoi
|
||||
};
|
||||
|
||||
if(str.size() > DOMAIN_MAX + 6)
|
||||
return false;
|
||||
|
||||
const char *start(str.data()), *const stop(start + str.size());
|
||||
return qi::parse(start, stop, rule);
|
||||
return valid(std::nothrow, parser::remote, str);
|
||||
}
|
||||
|
||||
void
|
||||
ircd::rfc3986::valid_remote(const string_view &str)
|
||||
try
|
||||
{
|
||||
static const auto &rule
|
||||
{
|
||||
parser::remote >> eoi
|
||||
};
|
||||
|
||||
if(str.size() > DOMAIN_MAX + 6)
|
||||
throw error
|
||||
{
|
||||
|
@ -338,39 +402,46 @@ try
|
|||
DOMAIN_MAX + 6
|
||||
};
|
||||
|
||||
const char *start(str.data()), *const stop(start + str.size());
|
||||
qi::parse(start, stop, eps > rule);
|
||||
valid(parser::remote, str);
|
||||
}
|
||||
catch(const qi::expectation_failure<const char *> &e)
|
||||
|
||||
bool
|
||||
ircd::rfc3986::valid_domain(std::nothrow_t,
|
||||
const string_view &str)
|
||||
{
|
||||
throw expectation_failure<error>{e};
|
||||
if(str.size() > DOMAIN_MAX)
|
||||
return false;
|
||||
|
||||
return valid(std::nothrow, parser::domain, str);
|
||||
}
|
||||
|
||||
void
|
||||
ircd::rfc3986::valid_domain(const string_view &str)
|
||||
{
|
||||
if(str.size() > DOMAIN_MAX)
|
||||
throw error
|
||||
{
|
||||
"String length %zu exceeds maximum of %zu characters",
|
||||
size(str),
|
||||
DOMAIN_MAX
|
||||
};
|
||||
|
||||
valid(parser::domain, str);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::rfc3986::valid_host(std::nothrow_t,
|
||||
const string_view &str)
|
||||
{
|
||||
static const auto &rule
|
||||
{
|
||||
parser::host >> eoi
|
||||
};
|
||||
|
||||
if(str.size() > DOMAIN_MAX)
|
||||
return false;
|
||||
|
||||
const char *start(str.data()), *const stop(start + str.size());
|
||||
return qi::parse(start, stop, rule);
|
||||
return valid(std::nothrow, parser::host, str);
|
||||
}
|
||||
|
||||
void
|
||||
ircd::rfc3986::valid_host(const string_view &str)
|
||||
try
|
||||
{
|
||||
static const auto &rule
|
||||
{
|
||||
parser::host >> eoi
|
||||
};
|
||||
|
||||
if(str.size() > DOMAIN_MAX)
|
||||
throw error
|
||||
{
|
||||
|
@ -379,112 +450,22 @@ try
|
|||
DOMAIN_MAX
|
||||
};
|
||||
|
||||
const char *start(str.data()), *const stop(start + str.size());
|
||||
qi::parse(start, stop, eps > rule);
|
||||
}
|
||||
catch(const qi::expectation_failure<const char *> &e)
|
||||
{
|
||||
throw expectation_failure<error>{e};
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::rfc3986::valid_domain(std::nothrow_t,
|
||||
const string_view &str)
|
||||
{
|
||||
static const auto &rule
|
||||
{
|
||||
parser::domain >> eoi
|
||||
};
|
||||
|
||||
if(str.size() > DOMAIN_MAX)
|
||||
return false;
|
||||
|
||||
const char *start(str.data()), *const stop(start + str.size());
|
||||
return qi::parse(start, stop, rule);
|
||||
}
|
||||
|
||||
void
|
||||
ircd::rfc3986::valid_domain(const string_view &str)
|
||||
try
|
||||
{
|
||||
static const auto &rule
|
||||
{
|
||||
parser::host >> eoi
|
||||
};
|
||||
|
||||
if(str.size() > DOMAIN_MAX)
|
||||
throw error
|
||||
{
|
||||
"String length %zu exceeds maximum of %zu characters",
|
||||
size(str),
|
||||
DOMAIN_MAX
|
||||
};
|
||||
|
||||
const char *start(str.data()), *const stop(start + str.size());
|
||||
qi::parse(start, stop, eps > rule);
|
||||
}
|
||||
catch(const qi::expectation_failure<const char *> &e)
|
||||
{
|
||||
throw expectation_failure<error>{e};
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::rfc3986::valid_literal(std::nothrow_t,
|
||||
const string_view &str)
|
||||
{
|
||||
static const auto &rule
|
||||
{
|
||||
(parser::ip6_literal >> eoi) |
|
||||
(parser::ip4_literal >> eoi)
|
||||
};
|
||||
|
||||
const char *start(str.data()), *const stop(start + str.size());
|
||||
return qi::parse(start, stop, rule);
|
||||
}
|
||||
|
||||
void
|
||||
ircd::rfc3986::valid_literal(const string_view &str)
|
||||
try
|
||||
{
|
||||
static const auto &rule
|
||||
{
|
||||
(parser::ip6_literal >> eoi) |
|
||||
(parser::ip4_literal >> eoi)
|
||||
};
|
||||
|
||||
const char *start(str.data()), *const stop(start + str.size());
|
||||
qi::parse(start, stop, eps > rule);
|
||||
}
|
||||
catch(const qi::expectation_failure<const char *> &e)
|
||||
{
|
||||
throw expectation_failure<error>{e};
|
||||
valid(parser::host, str);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::rfc3986::valid_hostname(std::nothrow_t,
|
||||
const string_view &str)
|
||||
{
|
||||
static const auto &rule
|
||||
{
|
||||
parser::hostname >> eoi
|
||||
};
|
||||
|
||||
if(str.size() > HOSTNAME_MAX)
|
||||
return false;
|
||||
|
||||
const char *start(str.data()), *const stop(start + str.size());
|
||||
return qi::parse(start, stop, rule);
|
||||
return valid(std::nothrow, parser::hostname, str);
|
||||
}
|
||||
|
||||
void
|
||||
ircd::rfc3986::valid_hostname(const string_view &str)
|
||||
try
|
||||
{
|
||||
static const auto &rule
|
||||
{
|
||||
parser::hostname >> eoi
|
||||
};
|
||||
|
||||
if(str.size() > HOSTNAME_MAX)
|
||||
throw error
|
||||
{
|
||||
|
@ -493,8 +474,35 @@ try
|
|||
HOSTNAME_MAX
|
||||
};
|
||||
|
||||
valid(parser::hostname, str);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::rfc3986::valid(std::nothrow_t,
|
||||
const parser::rule<> &rule,
|
||||
const string_view &str)
|
||||
{
|
||||
static const parser::rule<> only_rule
|
||||
{
|
||||
rule >> eoi
|
||||
};
|
||||
|
||||
const char *start(str.data()), *const stop(start + str.size());
|
||||
qi::parse(start, stop, eps > rule);
|
||||
return qi::parse(start, stop, only_rule);
|
||||
}
|
||||
|
||||
void
|
||||
ircd::rfc3986::valid(const parser::rule<> &rule,
|
||||
const string_view &str)
|
||||
try
|
||||
{
|
||||
static const parser::rule<> only_rule
|
||||
{
|
||||
rule >> eoi
|
||||
};
|
||||
|
||||
const char *start(str.data()), *const stop(start + str.size());
|
||||
qi::parse(start, stop, eps > only_rule);
|
||||
}
|
||||
catch(const qi::expectation_failure<const char *> &e)
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue