Use Boost X3 for URL parsing
This commit is contained in:
parent
efe6840d08
commit
7766a0f42b
@ -2,91 +2,65 @@
|
|||||||
#include "engine/polyline_compressor.hpp"
|
#include "engine/polyline_compressor.hpp"
|
||||||
|
|
||||||
#include <boost/fusion/include/adapt_struct.hpp>
|
#include <boost/fusion/include/adapt_struct.hpp>
|
||||||
#include <boost/phoenix.hpp>
|
#include <boost/spirit/home/x3.hpp>
|
||||||
#include <boost/spirit/include/qi.hpp>
|
#include <boost/spirit/home/x3/support/utility/annotate_on_success.hpp>
|
||||||
#include <boost/spirit/repository/include/qi_iter_pos.hpp>
|
#include <boost/spirit/home/x3/support/ast/position_tagged.hpp>
|
||||||
|
#include <boost/optional.hpp>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
BOOST_FUSION_ADAPT_STRUCT(osrm::server::api::ParsedURL,
|
BOOST_FUSION_ADAPT_STRUCT(osrm::server::api::ParsedURL,
|
||||||
(std::string, service)(unsigned, version)(std::string,
|
(std::string, service)
|
||||||
profile)(std::string, query))
|
(unsigned, version)
|
||||||
|
(std::string, profile)
|
||||||
// Keep impl. TU local
|
(std::string, query))
|
||||||
namespace
|
|
||||||
{
|
|
||||||
namespace ph = boost::phoenix;
|
|
||||||
namespace qi = boost::spirit::qi;
|
|
||||||
|
|
||||||
template <typename Iterator, typename Into> //
|
|
||||||
struct URLParser final : qi::grammar<Iterator, Into>
|
|
||||||
{
|
|
||||||
URLParser() : URLParser::base_type(start)
|
|
||||||
{
|
|
||||||
using boost::spirit::repository::qi::iter_pos;
|
|
||||||
|
|
||||||
identifier = qi::char_("a-zA-Z0-9_.~:-");
|
|
||||||
percent_encoding =
|
|
||||||
qi::char_('%') > qi::uint_parser<unsigned char, 16, 2, 2>()[qi::_val = qi::_1];
|
|
||||||
polyline_chars = qi::char_("a-zA-Z0-9_[]{}@?|\\~`^") | percent_encoding;
|
|
||||||
all_chars = polyline_chars | qi::char_("=,;:&().-");
|
|
||||||
|
|
||||||
service = +identifier;
|
|
||||||
version = qi::uint_;
|
|
||||||
profile = +identifier;
|
|
||||||
query = +all_chars;
|
|
||||||
|
|
||||||
// Example input: /route/v1/driving/7.416351,43.731205;7.420363,43.736189
|
|
||||||
|
|
||||||
start = qi::lit('/') > service > qi::lit('/') > qi::lit('v') > version > qi::lit('/') >
|
|
||||||
profile > qi::lit('/') >
|
|
||||||
qi::omit[iter_pos[ph::bind(&osrm::server::api::ParsedURL::prefix_length, qi::_val) =
|
|
||||||
qi::_1 - qi::_r1]] > query;
|
|
||||||
|
|
||||||
BOOST_SPIRIT_DEBUG_NODES((start)(service)(version)(profile)(query))
|
|
||||||
}
|
|
||||||
|
|
||||||
qi::rule<Iterator, Into> start;
|
|
||||||
|
|
||||||
qi::rule<Iterator, std::string()> service;
|
|
||||||
qi::rule<Iterator, unsigned()> version;
|
|
||||||
qi::rule<Iterator, std::string()> profile;
|
|
||||||
qi::rule<Iterator, std::string()> query;
|
|
||||||
|
|
||||||
qi::rule<Iterator, char()> identifier;
|
|
||||||
qi::rule<Iterator, char()> all_chars;
|
|
||||||
qi::rule<Iterator, char()> polyline_chars;
|
|
||||||
qi::rule<Iterator, char()> percent_encoding;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace osrm::server::api
|
namespace osrm::server::api
|
||||||
{
|
{
|
||||||
|
namespace x3 = boost::spirit::x3;
|
||||||
|
|
||||||
boost::optional<ParsedURL> parseURL(std::string::iterator &iter, const std::string::iterator end)
|
struct ParsedURLClass : x3::annotate_on_success {};
|
||||||
{
|
const x3::rule<struct Service, std::string> service = "service";
|
||||||
using It = std::decay<decltype(iter)>::type;
|
const x3::rule<struct Version, unsigned> version = "version";
|
||||||
|
const x3::rule<struct Profile, std::string> profile = "profile";
|
||||||
|
const x3::rule<struct Query, std::string> query = "query";
|
||||||
|
const x3::rule<struct ParsedURL, ParsedURL> start = "start";
|
||||||
|
|
||||||
static URLParser<It, ParsedURL(It)> const parser;
|
const auto identifier = x3::char_("a-zA-Z0-9_.~:-");
|
||||||
ParsedURL out;
|
const auto percent_encoding = x3::char_('%') >> x3::uint_parser<unsigned char, 16, 2, 2>();
|
||||||
|
const auto polyline_chars = x3::char_("a-zA-Z0-9_[]{}@?|\\~`^") | percent_encoding;
|
||||||
|
const auto all_chars = polyline_chars | x3::char_("=,;:&().-");
|
||||||
|
|
||||||
try
|
const auto service_def = +identifier;
|
||||||
|
const auto version_def = x3::uint_;
|
||||||
|
const auto profile_def = +identifier;
|
||||||
|
const auto query_def = +all_chars;
|
||||||
|
|
||||||
|
const auto start_def =
|
||||||
|
x3::lit('/') > service > x3::lit('/') > x3::lit('v') > version > x3::lit('/') > profile > x3::lit('/') > query;
|
||||||
|
|
||||||
|
BOOST_SPIRIT_DEFINE(service, version, profile, query, start)
|
||||||
|
|
||||||
|
boost::optional<ParsedURL> parseURL(std::string::iterator &iter, const std::string::iterator end)
|
||||||
{
|
{
|
||||||
const auto ok = boost::spirit::qi::parse(iter, end, parser(boost::phoenix::val(iter)), out);
|
ParsedURL out;
|
||||||
|
|
||||||
if (ok && iter == end)
|
try
|
||||||
return boost::make_optional(out);
|
{
|
||||||
}
|
auto iter_copy = iter;
|
||||||
catch (const qi::expectation_failure<It> &failure)
|
bool r = x3::phrase_parse(iter_copy, end, start, x3::space, out);
|
||||||
{
|
|
||||||
// The grammar above using expectation parsers ">" does not automatically increment the
|
|
||||||
// iterator to the failing position. Extract the position from the exception ourselves.
|
|
||||||
iter = failure.first;
|
|
||||||
}
|
|
||||||
|
|
||||||
return boost::none;
|
if (r && iter_copy == end)
|
||||||
}
|
{
|
||||||
|
iter = iter_copy;
|
||||||
|
return boost::make_optional(out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const x3::expectation_failure<std::string::iterator> &)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
return boost::none;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace osrm::server::api
|
} // namespace osrm::server::api
|
||||||
|
Loading…
Reference in New Issue
Block a user