Add viaroute suport for new API
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
#include "server/api/route_parameters_parser.hpp"
|
||||
#include "server/api/route_parameters_grammar.hpp"
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace server
|
||||
{
|
||||
namespace api
|
||||
{
|
||||
|
||||
boost::optional<engine::api::RouteParameters> parseRouteParameters(std::string::iterator& iter, std::string::iterator end)
|
||||
{
|
||||
RouteParametersGrammar grammar;
|
||||
const auto result = boost::spirit::qi::parse(iter, end, grammar);
|
||||
|
||||
boost::optional<engine::api::RouteParameters> parameters;
|
||||
if (result && iter == end)
|
||||
{
|
||||
parameters = std::move(grammar.route_parameters);
|
||||
}
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
#include "server/api/url_parser.hpp"
|
||||
|
||||
#include "engine/polyline_compressor.hpp"
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/spirit/include/qi_char_.hpp>
|
||||
#include <boost/spirit/include/qi_grammar.hpp>
|
||||
#include <boost/spirit/include/qi_uint.hpp>
|
||||
#include <boost/spirit/include/qi_real.hpp>
|
||||
#include <boost/spirit/include/qi_lit.hpp>
|
||||
#include <boost/spirit/include/qi_action.hpp>
|
||||
#include <boost/spirit/include/qi_as_string.hpp>
|
||||
#include <boost/spirit/include/qi_operator.hpp>
|
||||
#include <boost/spirit/include/qi_plus.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace server
|
||||
{
|
||||
namespace api
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
namespace qi = boost::spirit::qi;
|
||||
using Iterator = std::string::iterator;
|
||||
struct URLGrammar : boost::spirit::qi::grammar<Iterator>
|
||||
{
|
||||
URLGrammar() : URLGrammar::base_type(url_rule)
|
||||
{
|
||||
const auto set_service = [this](std::string &service)
|
||||
{
|
||||
parsed_url.service = std::move(service);
|
||||
};
|
||||
const auto set_version = [this](const unsigned version)
|
||||
{
|
||||
parsed_url.version = version;
|
||||
};
|
||||
const auto set_profile = [this](std::string &profile)
|
||||
{
|
||||
parsed_url.profile = std::move(profile);
|
||||
};
|
||||
const auto set_options = [this](std::string &options)
|
||||
{
|
||||
parsed_url.options = std::move(options);
|
||||
};
|
||||
const auto add_coordinate = [this](const boost::fusion::vector<double, double> &lonLat)
|
||||
{
|
||||
parsed_url.coordinates.emplace_back(
|
||||
util::FixedPointCoordinate(boost::fusion::at_c<1>(lonLat) * COORDINATE_PRECISION,
|
||||
boost::fusion::at_c<0>(lonLat) * COORDINATE_PRECISION));
|
||||
};
|
||||
const auto polyline_to_coordinates = [this](const std::string &polyline)
|
||||
{
|
||||
parsed_url.coordinates = engine::decodePolyline(polyline);
|
||||
};
|
||||
|
||||
alpha_numeral = qi::char_("a-zA-Z0-9");
|
||||
polyline_chars = qi::char_("a-zA-Z0-9_.--[]{}@?|\\%~`^");
|
||||
all_chars = polyline_chars | qi::char_("=,;:&");
|
||||
|
||||
polyline_rule = qi::as_string[qi::lit("polyline(") >> +polyline_chars >>
|
||||
qi::lit(")")][polyline_to_coordinates];
|
||||
location_rule = (qi::double_ >> qi::lit(',') >> qi::double_)[add_coordinate];
|
||||
query_rule = (location_rule % ';') | polyline_rule;
|
||||
|
||||
service_rule = +alpha_numeral;
|
||||
version_rule = qi::uint_;
|
||||
profile_rule = +alpha_numeral;
|
||||
options_rule = *all_chars;
|
||||
|
||||
url_rule = qi::lit('/') >> service_rule[set_service] >> qi::lit('/') >> qi::lit('v') >>
|
||||
version_rule[set_version] >> qi::lit('/') >> profile_rule[set_profile] >>
|
||||
qi::lit('/') >> query_rule >> -(qi::lit('?') >> options_rule[set_options]);
|
||||
}
|
||||
|
||||
ParsedURL parsed_url;
|
||||
|
||||
qi::rule<Iterator> url_rule;
|
||||
qi::rule<Iterator, std::string()> options_rule, service_rule, profile_rule;
|
||||
qi::rule<Iterator> query_rule, polyline_rule, location_rule;
|
||||
qi::rule<Iterator, unsigned()> version_rule;
|
||||
qi::rule<Iterator, char()> alpha_numeral, all_chars, polyline_chars;
|
||||
};
|
||||
}
|
||||
|
||||
boost::optional<ParsedURL> parseURL(std::string::iterator &iter, std::string::iterator end)
|
||||
{
|
||||
boost::optional<ParsedURL> parsed_url;
|
||||
|
||||
URLGrammar grammar;
|
||||
const auto result = boost::spirit::qi::parse(iter, end, grammar);
|
||||
|
||||
if (result && iter == end)
|
||||
{
|
||||
parsed_url = std::move(grammar.parsed_url);
|
||||
}
|
||||
|
||||
return parsed_url;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,7 @@ void Connection::handle_read(const boost::system::error_code &error, std::size_t
|
||||
if (result == RequestParser::RequestStatus::valid)
|
||||
{
|
||||
current_request.endpoint = TCP_socket.remote_endpoint().address();
|
||||
request_handler.handle_request(current_request, current_reply);
|
||||
request_handler.HandleRequest(current_request, current_reply);
|
||||
|
||||
// compress the result w/ gzip/deflate if requested
|
||||
switch (compression_type)
|
||||
|
||||
@@ -10,9 +10,9 @@ namespace http
|
||||
{
|
||||
|
||||
const char ok_html[] = "";
|
||||
const char bad_request_html[] = "{\"status\": 400,\"status_message\":\"Bad Request\"}";
|
||||
const char bad_request_html[] = "";
|
||||
const char internal_server_error_html[] =
|
||||
"{\"status\": 500,\"status_message\":\"Internal Server Error\"}";
|
||||
"{\"code\": \"internal-error\",\"message\":\"Internal Server Error\"}";
|
||||
const char seperators[] = {':', ' '};
|
||||
const char crlf[] = {'\r', '\n'};
|
||||
const std::string http_ok_string = "HTTP/1.0 200 OK\r\n";
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "server/request_handler.hpp"
|
||||
#include "server/service_handler.hpp"
|
||||
|
||||
#include "server/api_grammar.hpp"
|
||||
#include "server/api/url_parser.hpp"
|
||||
#include "server/http/reply.hpp"
|
||||
#include "server/http/request.hpp"
|
||||
|
||||
@@ -9,7 +10,7 @@
|
||||
#include "util/string_util.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include "engine/route_parameters.hpp"
|
||||
#include "engine/status.hpp"
|
||||
#include "util/json_container.hpp"
|
||||
#include "osrm/osrm.hpp"
|
||||
|
||||
@@ -28,11 +29,22 @@ namespace osrm
|
||||
namespace server
|
||||
{
|
||||
|
||||
RequestHandler::RequestHandler() : routing_machine(nullptr) {}
|
||||
|
||||
void RequestHandler::handle_request(const http::request ¤t_request,
|
||||
void RequestHandler::RegisterServiceHandler(std::unique_ptr<ServiceHandler> service_handler_)
|
||||
{
|
||||
service_handler = std::move(service_handler_);
|
||||
}
|
||||
|
||||
void RequestHandler::HandleRequest(const http::request ¤t_request,
|
||||
http::reply ¤t_reply)
|
||||
{
|
||||
if (!service_handler)
|
||||
{
|
||||
current_reply = http::reply::stock_reply(http::reply::internal_server_error);
|
||||
util::SimpleLogger().Write(logWARNING) << "No service handler registered." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
util::json::Object json_result;
|
||||
|
||||
// parse command
|
||||
@@ -67,84 +79,49 @@ void RequestHandler::handle_request(const http::request ¤t_request,
|
||||
<< current_request.agent << (0 == current_request.agent.length() ? "- " : " ")
|
||||
<< request_string;
|
||||
|
||||
engine::RouteParameters route_parameters;
|
||||
APIGrammarParser api_parser(&route_parameters);
|
||||
|
||||
auto api_iterator = request_string.begin();
|
||||
const bool result =
|
||||
boost::spirit::qi::parse(api_iterator, request_string.end(), api_parser);
|
||||
auto maybe_parsed_url = api::parseURL(api_iterator, request_string.end());;
|
||||
|
||||
// check if the was an error with the request
|
||||
if (result && api_iterator == request_string.end())
|
||||
if (maybe_parsed_url && api_iterator == request_string.end())
|
||||
{
|
||||
// parsing done, lets call the right plugin to handle the request
|
||||
BOOST_ASSERT_MSG(routing_machine != nullptr, "pointer not init'ed");
|
||||
|
||||
if (!route_parameters.jsonp_parameter.empty())
|
||||
{ // prepend response with jsonp parameter
|
||||
const std::string json_p = (route_parameters.jsonp_parameter + "(");
|
||||
current_reply.content.insert(current_reply.content.end(), json_p.begin(),
|
||||
json_p.end());
|
||||
}
|
||||
|
||||
const int return_code = routing_machine->RunQuery(route_parameters, json_result);
|
||||
json_result.values["status"] = return_code;
|
||||
// 4xx bad request return code
|
||||
if (return_code / 100 == 4)
|
||||
const engine::Status status = service_handler->RunQuery(std::move(*maybe_parsed_url), json_result);
|
||||
if (status != engine::Status::Ok)
|
||||
{
|
||||
// 4xx bad request return code
|
||||
current_reply.status = http::reply::bad_request;
|
||||
current_reply.content.clear();
|
||||
route_parameters.output_format.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// 2xx valid request
|
||||
BOOST_ASSERT(return_code / 100 == 2);
|
||||
BOOST_ASSERT(status == engine::Status::Ok);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto position = std::distance(request_string.begin(), api_iterator);
|
||||
const auto context_begin = request_string.begin() + std::max(position - 3UL, 0UL);
|
||||
const auto context_end = request_string.begin() + std::min(position + 3UL, request_string.size());
|
||||
std::string context(context_begin, context_end);
|
||||
|
||||
current_reply.status = http::reply::bad_request;
|
||||
json_result.values["status"] = http::reply::bad_request;
|
||||
json_result.values["status_message"] =
|
||||
"Query string malformed close to position " + std::to_string(position);
|
||||
json_result.values["code"] = "invalid-url";
|
||||
json_result.values["message"] =
|
||||
"URL string malformed close to position " + std::to_string(position) + ": \"" + context + "\"";
|
||||
}
|
||||
|
||||
current_reply.headers.emplace_back("Access-Control-Allow-Origin", "*");
|
||||
current_reply.headers.emplace_back("Access-Control-Allow-Methods", "GET");
|
||||
current_reply.headers.emplace_back("Access-Control-Allow-Headers",
|
||||
"X-Requested-With, Content-Type");
|
||||
current_reply.headers.emplace_back("Content-Type", "application/json; charset=UTF-8");
|
||||
current_reply.headers.emplace_back("Content-Disposition",
|
||||
"inline; filename=\"response.json\"");
|
||||
|
||||
if (route_parameters.service == "tile" && json_result.values.find("pbf") != json_result.values.end())
|
||||
{
|
||||
std::copy(json_result.values["pbf"].get<osrm::util::json::Buffer>().value.cbegin(),
|
||||
json_result.values["pbf"].get<osrm::util::json::Buffer>().value.cend(),
|
||||
std::back_inserter(current_reply.content));
|
||||
util::json::render(current_reply.content, json_result);
|
||||
|
||||
current_reply.headers.emplace_back("Content-Type", "application/x-protobuf");
|
||||
}
|
||||
else if (route_parameters.jsonp_parameter.empty())
|
||||
{ // json file
|
||||
util::json::render(current_reply.content, json_result);
|
||||
current_reply.headers.emplace_back("Content-Type", "application/json; charset=UTF-8");
|
||||
current_reply.headers.emplace_back("Content-Disposition",
|
||||
"inline; filename=\"response.json\"");
|
||||
}
|
||||
else
|
||||
{ // jsonp
|
||||
util::json::render(current_reply.content, json_result);
|
||||
current_reply.headers.emplace_back("Content-Type", "text/javascript; charset=UTF-8");
|
||||
current_reply.headers.emplace_back("Content-Disposition",
|
||||
"inline; filename=\"response.js\"");
|
||||
}
|
||||
// set headers
|
||||
current_reply.headers.emplace_back("Content-Length",
|
||||
std::to_string(current_reply.content.size()));
|
||||
if (!route_parameters.jsonp_parameter.empty())
|
||||
{ // append brace to jsonp response
|
||||
current_reply.content.push_back(')');
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
@@ -154,6 +131,5 @@ void RequestHandler::handle_request(const http::request ¤t_request,
|
||||
}
|
||||
}
|
||||
|
||||
void RequestHandler::RegisterRoutingMachine(OSRM *osrm) { routing_machine = osrm; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
#include "server/service/route_service.hpp"
|
||||
|
||||
#include "engine/api/route_parameters.hpp"
|
||||
#include "server/api/route_parameters_parser.hpp"
|
||||
|
||||
#include "util/json_container.hpp"
|
||||
|
||||
#include <boost/format.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace server
|
||||
{
|
||||
namespace service
|
||||
{
|
||||
|
||||
namespace {
|
||||
|
||||
const constexpr char PARAMETER_SIZE_MISMATCH_MSG[] = "Number of elements in %1% size %2% does not match coordinate size %3%";
|
||||
|
||||
template<typename ParamT>
|
||||
bool constrainParamSize(const char* msg_template, const char* name, const ParamT& param, const std::size_t target_size, std::string& help)
|
||||
{
|
||||
if (param.size() > 0 && param.size() != target_size)
|
||||
{
|
||||
help = (boost::format(msg_template) % name % param.size() % target_size).str();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string getWrongOptionHelp(const engine::api::RouteParameters& parameters)
|
||||
{
|
||||
std::string help;
|
||||
|
||||
const auto coord_size = parameters.coordinates.size();
|
||||
|
||||
const bool param_size_mismatch = constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "hints", parameters.hints, coord_size, help)
|
||||
|| constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "bearings", parameters.bearings, coord_size, help)
|
||||
|| constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "radiuses", parameters.radiuses, coord_size, help)
|
||||
|| constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "uturns", parameters.uturns, coord_size, help);
|
||||
|
||||
if (!param_size_mismatch && parameters.coordinates.size() < 2)
|
||||
{
|
||||
help = "Number of coordinates needs to be at least two.";
|
||||
}
|
||||
|
||||
return help;
|
||||
}
|
||||
} // anon. ns
|
||||
|
||||
engine::Status RouteService::RunQuery(std::vector<util::FixedPointCoordinate> coordinates,
|
||||
std::string &options,
|
||||
util::json::Object &json_result)
|
||||
{
|
||||
|
||||
auto options_iterator = options.begin();
|
||||
auto parameters = api::parseRouteParameters(options_iterator, options.end());
|
||||
if (!parameters || options_iterator != options.end())
|
||||
{
|
||||
const auto position = std::distance(options.begin(), options_iterator);
|
||||
json_result.values["code"] = "invalid-options";
|
||||
json_result.values["message"] =
|
||||
"Options string malformed close to position " + std::to_string(position);
|
||||
return engine::Status::Error;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(parameters);
|
||||
parameters->coordinates = std::move(coordinates);
|
||||
|
||||
if (!parameters->IsValid())
|
||||
{
|
||||
json_result.values["code"] = "invalid-options";
|
||||
json_result.values["message"] = getWrongOptionHelp(*parameters);
|
||||
return engine::Status::Error;
|
||||
}
|
||||
BOOST_ASSERT(parameters->IsValid());
|
||||
|
||||
return BaseService::routing_machine.Route(*parameters, json_result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#include "server/service_handler.hpp"
|
||||
|
||||
#include "server/service/route_service.hpp"
|
||||
|
||||
#include "server/api/parsed_url.hpp"
|
||||
#include "util/json_util.hpp"
|
||||
#include "util/make_unique.hpp"
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace server
|
||||
{
|
||||
ServiceHandler::ServiceHandler(osrm::EngineConfig &config) : routing_machine(config)
|
||||
{
|
||||
service_map["route"] = util::make_unique<service::RouteService>(routing_machine);
|
||||
}
|
||||
|
||||
engine::Status ServiceHandler::RunQuery(api::ParsedURL parsed_url, util::json::Object &json_result)
|
||||
{
|
||||
const auto& service_iter = service_map.find(parsed_url.service);
|
||||
if (service_iter == service_map.end())
|
||||
{
|
||||
json_result.values["code"] = "invalid-service";
|
||||
json_result.values["message"] = "Service " + parsed_url.service + " not found!";
|
||||
return engine::Status::Error;
|
||||
}
|
||||
auto &service = service_iter->second;
|
||||
|
||||
if (service->GetVersion() != parsed_url.version)
|
||||
{
|
||||
json_result.values["code"] = "invalid-version";
|
||||
json_result.values["message"] = "Service " + parsed_url.service + " not found!";
|
||||
return engine::Status::Error;
|
||||
}
|
||||
|
||||
return service->RunQuery(std::move(parsed_url.coordinates), parsed_url.options, json_result);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user