// 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 #include #include #include BOOST_FUSION_ADAPT_TPL_STRUCT ( (FwdIter), (boost::network::uri::detail::hierarchical_part)(FwdIter), (boost::optional >, user_info) (boost::optional >, host) (boost::optional >, port) (boost::optional >, path) ); BOOST_FUSION_ADAPT_TPL_STRUCT ( (FwdIter), (boost::network::uri::detail::uri_parts)(FwdIter), (boost::iterator_range, scheme) (boost::network::uri::detail::hierarchical_part, hier_part) (boost::optional >, query) (boost::optional >, 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()> { 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 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() ]; // 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()) >> qi::attr(iterator_range()) >> qi::attr(iterator_range()) >> ( path_absolute | path_rootless | path_empty ) ) ; start %= (scheme >> ':') >> hier_part >> -('?' >> query) >> -('#' >> fragment) ; } qi::rule::value_type()> gen_delims, sub_delims, reserved, unreserved; qi::rule pct_encoded, pchar; qi::rule segment, segment_nz, segment_nz_nc; qi::rule()> path_abempty, path_absolute, path_rootless, path_empty; qi::rule dec_octet, ipv4address, reg_name, ipv6address, ipvfuture, ip_literal; qi::rule h16, ls32; qi::rule()> host, port; qi::rule()> scheme, user_info, query, fragment; qi::rule()> hier_part; // actual uri parser qi::rule()> start; }; bool parse(std::string::const_iterator first, std::string::const_iterator last, uri_parts &parts) { namespace qi = boost::spirit::qi; static detail::uri_grammar grammar; bool is_valid = qi::parse(first, last, grammar, parts); return is_valid && (first == last); } } // namespace detail } // namespace uri } // namespace network } // namespace boost