0
0
Fork 0
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:
Jason Volk 2019-03-25 12:07:06 -07:00
parent c5088c3af2
commit 46346f504e
2 changed files with 189 additions and 151 deletions

View file

@ -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 &);
}

View file

@ -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)
{