Files
2026-06-01 12:46:52 +02:00

240 lines
8.2 KiB
C++

// Copyright 2009, 2010, 2011, 2012 Dean Michael Berris, Jeroen Habraken, Glyn Matthews.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/network/uri/detail/uri_parts.hpp>
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/home/qi.hpp>
#include <boost/fusion/adapted/struct/adapt_struct.hpp>
BOOST_FUSION_ADAPT_TPL_STRUCT
(
(FwdIter),
(boost::network::uri::detail::hierarchical_part)(FwdIter),
(boost::optional<boost::iterator_range<FwdIter> >, user_info)
(boost::optional<boost::iterator_range<FwdIter> >, host)
(boost::optional<boost::iterator_range<FwdIter> >, port)
(boost::optional<boost::iterator_range<FwdIter> >, path)
);
BOOST_FUSION_ADAPT_TPL_STRUCT
(
(FwdIter),
(boost::network::uri::detail::uri_parts)(FwdIter),
(boost::iterator_range<FwdIter>, scheme)
(boost::network::uri::detail::hierarchical_part<FwdIter>, hier_part)
(boost::optional<boost::iterator_range<FwdIter> >, query)
(boost::optional<boost::iterator_range<FwdIter> >, fragment)
);
namespace boost {
namespace network {
namespace uri {
namespace detail {
namespace qi = boost::spirit::qi;
template <
class String
>
struct uri_grammar : qi::grammar<
typename String::const_iterator
, detail::uri_parts<typename String::const_iterator>()> {
typedef String string_type;
typedef typename String::const_iterator const_iterator;
uri_grammar() : uri_grammar::base_type(start, "uri") {
// gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
gen_delims %= qi::char_(":/?#[]@");
// sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
sub_delims %= qi::char_("!$&'()*+,;=");
// reserved = gen-delims / sub-delims
reserved %= gen_delims | sub_delims;
// unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
unreserved %= qi::alnum | qi::char_("-._~");
// pct-encoded = "%" HEXDIG HEXDIG
pct_encoded %= qi::char_("%") >> qi::repeat(2)[qi::xdigit];
// pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
pchar %= qi::raw[
unreserved | pct_encoded | sub_delims | qi::char_(":@")
];
// segment = *pchar
segment %= qi::raw[*pchar];
// segment-nz = 1*pchar
segment_nz %= qi::raw[+pchar];
// segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
segment_nz_nc %= qi::raw[
+(unreserved | pct_encoded | sub_delims | qi::char_("@"))
];
// path-abempty = *( "/" segment )
path_abempty %=
qi::raw[*(qi::char_("/") >> segment)]
;
// path-absolute = "/" [ segment-nz *( "/" segment ) ]
path_absolute %=
qi::raw[
qi::char_("/")
>> -(segment_nz >> *(qi::char_("/") >> segment))
]
;
// path-rootless = segment-nz *( "/" segment )
path_rootless %=
qi::raw[segment_nz >> *(qi::char_("/") >> segment)]
;
// path-empty = 0<pchar>
path_empty %=
qi::raw[qi::eps]
;
// scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
scheme %=
qi::raw[qi::alpha >> *(qi::alnum | qi::char_("+.-"))]
;
// user_info = *( unreserved / pct-encoded / sub-delims / ":" )
user_info %=
qi::raw[*(unreserved | pct_encoded | sub_delims | qi::char_(":"))]
;
ip_literal %=
qi::lit('[') >> (ipv6address | ipvfuture) >> ']'
;
ipvfuture %=
qi::lit('v') >> +qi::xdigit >> '.' >> +( unreserved | sub_delims | ':')
;
ipv6address %= qi::raw[
qi::repeat(6)[h16 >> ':'] >> ls32
| "::" >> qi::repeat(5)[h16 >> ':'] >> ls32
| qi::raw[ h16] >> "::" >> qi::repeat(4)[h16 >> ':'] >> ls32
| qi::raw[ +(*(h16 >> ':')) >> h16] >> "::" >> qi::repeat(3)[h16 >> ':'] >> ls32
| qi::raw[qi::repeat(2)[*(h16 >> ':')] >> h16] >> "::" >> qi::repeat(2)[h16 >> ':'] >> ls32
| qi::raw[qi::repeat(3)[*(h16 >> ':')] >> h16] >> "::" >> h16 >> ':' >> ls32
| qi::raw[qi::repeat(4)[*(h16 >> ':')] >> h16] >> "::" >> ls32
| qi::raw[qi::repeat(5)[*(h16 >> ':')] >> h16] >> "::" >> h16
| qi::raw[qi::repeat(6)[*(h16 >> ':')] >> h16] >> "::"
];
// ls32 = ( h16 ":" h16 ) / IPv4address
ls32 %= (h16 >> ':' >> h16) | ipv4address
;
// h16 = 1*4HEXDIG
h16 %= qi::repeat(1, 4)[qi::xdigit]
;
// dec-octet = DIGIT / %x31-39 DIGIT / "1" 2DIGIT / "2" %x30-34 DIGIT / "25" %x30-35
dec_octet %=
!(qi::lit('0') >> qi::digit)
>> qi::raw[
qi::uint_parser<boost::uint8_t, 10, 1, 3>()
];
// IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
ipv4address %= qi::raw[
dec_octet >> qi::repeat(3)[qi::lit('.') >> dec_octet]
];
// reg-name = *( unreserved / pct-encoded / sub-delims )
reg_name %= qi::raw[
*(unreserved | pct_encoded | sub_delims)
];
// TODO, host = IP-literal / IPv4address / reg-name
host %=
qi::raw[ip_literal | ipv4address | reg_name]
;
// port %= qi::ushort_;
port %=
qi::raw[*qi::digit]
;
// query = *( pchar / "/" / "?" )
query %=
qi::raw[*(pchar | qi::char_("/?"))]
;
// fragment = *( pchar / "/" / "?" )
fragment %=
qi::raw[*(pchar | qi::char_("/?"))]
;
// hier-part = "//" authority path-abempty / path-absolute / path-rootless / path-empty
// authority = [ userinfo "@" ] host [ ":" port ]
hier_part %=
(
(("//" >> user_info >> '@') | "//")
>> host
>> -(':' >> port)
>> path_abempty
)
|
(
qi::attr(iterator_range<const_iterator>())
>> qi::attr(iterator_range<const_iterator>())
>> qi::attr(iterator_range<const_iterator>())
>> (
path_absolute
| path_rootless
| path_empty
)
)
;
start %=
(scheme >> ':')
>> hier_part
>> -('?' >> query)
>> -('#' >> fragment)
;
}
qi::rule<const_iterator, typename iterator_range<const_iterator>::value_type()>
gen_delims, sub_delims, reserved, unreserved;
qi::rule<const_iterator, string_type()>
pct_encoded, pchar;
qi::rule<const_iterator, string_type()>
segment, segment_nz, segment_nz_nc;
qi::rule<const_iterator, iterator_range<const_iterator>()>
path_abempty, path_absolute, path_rootless, path_empty;
qi::rule<const_iterator, string_type()>
dec_octet, ipv4address, reg_name, ipv6address, ipvfuture, ip_literal;
qi::rule<const_iterator, string_type()>
h16, ls32;
qi::rule<const_iterator, iterator_range<const_iterator>()>
host, port;
qi::rule<const_iterator, iterator_range<const_iterator>()>
scheme, user_info, query, fragment;
qi::rule<const_iterator, hierarchical_part<const_iterator>()>
hier_part;
// actual uri parser
qi::rule<const_iterator, uri_parts<const_iterator>()> start;
};
bool parse(std::string::const_iterator first,
std::string::const_iterator last,
uri_parts<std::string::const_iterator> &parts) {
namespace qi = boost::spirit::qi;
static detail::uri_grammar<std::string> grammar;
bool is_valid = qi::parse(first, last, grammar, parts);
return is_valid && (first == last);
}
} // namespace detail
} // namespace uri
} // namespace network
} // namespace boost