240 lines
8.2 KiB
C++
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
|