diff --git a/Plugins/HelloWorldPlugin.h b/Plugins/HelloWorldPlugin.h
index 345514f13..d8b5cae49 100644
--- a/Plugins/HelloWorldPlugin.h
+++ b/Plugins/HelloWorldPlugin.h
@@ -25,16 +25,14 @@ public:
reply.status = http::Reply::ok;
reply.content.append("
Hello World Demonstration DocumentHello, World!
");
std::stringstream content;
- content << "Number of parameters: " << routeParameters.parameters.size() << "
";
- for(unsigned i = 0; i < routeParameters.parameters.size(); i++) {
- content << routeParameters.parameters[i] << "
";
- }
- content << "Number Of Options: " << routeParameters.options.Size() << "
";
- RouteParameters::OptionsIterator optionsIT = routeParameters.options.begin();
- for(;optionsIT != routeParameters.options.end(); optionsIT++) {
- content << "param = " << optionsIT->first << ": ";
- content << "option = " << optionsIT->second << "
";
- }
+ content << "Number of locations: " << routeParameters.coordinates.size() << "
\n";
+ for(unsigned i = 0; i < routeParameters.coordinates.size(); ++i) {
+ content << " [" << i << "] " << routeParameters.coordinates[i].lat/100000. << "," << routeParameters.coordinates[i].lon/100000. << "
\n";
+ }
+ content << "Number of hints: " << routeParameters.hints.size() << "
\n";
+ for(unsigned i = 0; i < routeParameters.hints.size(); ++i) {
+ content << " [" << i << "] " << routeParameters.hints[i] << "
\n";
+ }
reply.content.append(content.str());
reply.content.append("");
}
diff --git a/Plugins/LocatePlugin.h b/Plugins/LocatePlugin.h
index 9b73674c2..39d83b345 100644
--- a/Plugins/LocatePlugin.h
+++ b/Plugins/LocatePlugin.h
@@ -41,21 +41,11 @@ public:
std::string GetVersionString() const { return std::string("0.3 (DL)"); }
void HandleRequest(const RouteParameters & routeParameters, http::Reply& reply) {
//check number of parameters
- if(!routeParameters.viaPoints.size()) {
+ if(!routeParameters.coordinates.size()) {
reply = http::Reply::stockReply(http::Reply::badRequest);
return;
}
- std::vector textCoord;
- stringSplit (routeParameters.viaPoints[0], ',', textCoord);
- if(textCoord.size() != 2) {
- reply = http::Reply::stockReply(http::Reply::badRequest);
- return;
- }
-
- int lat = 100000.*atof(textCoord[0].c_str());
- int lon = 100000.*atof(textCoord[1].c_str());
- _Coordinate myCoordinate(lat, lon);
- if(false == checkCoord(myCoordinate)) {
+ if(false == checkCoord(routeParameters.coordinates[0])) {
reply = http::Reply::stockReply(http::Reply::badRequest);
return;
}
@@ -65,15 +55,15 @@ public:
std::string JSONParameter, tmp;
//json
- JSONParameter = routeParameters.options.Find("jsonp");
- if("" != JSONParameter) {
+// JSONParameter = routeParameters.options.Find("jsonp");
+ if("" != routeParameters.jsonpParameter) {
reply.content += JSONParameter;
reply.content += "(";
}
reply.status = http::Reply::ok;
reply.content += ("{");
reply.content += ("\"version\":0.3,");
- if(!nodeHelpDesk->FindNearestNodeCoordForLatLon(myCoordinate, result)) {
+ if(!nodeHelpDesk->FindNearestNodeCoordForLatLon(routeParameters.coordinates[0], result)) {
reply.content += ("\"status\":207,");
reply.content += ("\"mapped_coordinate\":[]");
} else {
diff --git a/Plugins/NearestPlugin.h b/Plugins/NearestPlugin.h
index 54910a97f..53dc1bd51 100644
--- a/Plugins/NearestPlugin.h
+++ b/Plugins/NearestPlugin.h
@@ -29,7 +29,6 @@ or see http://www.gnu.org/licenses/agpl.txt.
#include "../Server/DataStructures/QueryObjectsStorage.h"
#include "../DataStructures/NodeInformationHelpDesk.h"
-#include "../DataStructures/HashTable.h"
#include "../Util/StringUtil.h"
/*
@@ -47,43 +46,25 @@ public:
std::string GetVersionString() const { return std::string("0.3 (DL)"); }
void HandleRequest(const RouteParameters & routeParameters, http::Reply& reply) {
//check number of parameters
- if(!routeParameters.viaPoints.size()) {
+ if(!routeParameters.coordinates.size()) {
reply = http::Reply::stockReply(http::Reply::badRequest);
return;
}
- std::vector textCoord;
- stringSplit (routeParameters.viaPoints[0], ',', textCoord);
- if(textCoord.size() != 2) {
- reply = http::Reply::stockReply(http::Reply::badRequest);
- return;
- }
-
- int lat = 100000.*atof(textCoord[0].c_str());
- int lon = 100000.*atof(textCoord[1].c_str());
- _Coordinate myCoordinate(lat, lon);
- if(false == checkCoord(myCoordinate)) {
+ if(false == checkCoord(routeParameters.coordinates[0])) {
reply = http::Reply::stockReply(http::Reply::badRequest);
return;
}
- unsigned zoomLevel = 18;
- if(routeParameters.options.Find("z") != ""){
- zoomLevel = atoi(routeParameters.options.Find("z").c_str());
- if(18 < zoomLevel)
- zoomLevel = 18;
- }
-
//query to helpdesk
PhantomNode result;
- nodeHelpDesk->FindPhantomNodeForCoordinate(myCoordinate, result, zoomLevel);
+ nodeHelpDesk->FindPhantomNodeForCoordinate(routeParameters.coordinates[0], result, routeParameters.zoomLevel);
std::string tmp;
std::string JSONParameter;
//json
- JSONParameter = routeParameters.options.Find("jsonp");
- if("" != JSONParameter) {
- reply.content += JSONParameter;
+ if("" != routeParameters.jsonpParameter) {
+ reply.content += routeParameters.jsonpParameter;
reply.content += "(";
}
diff --git a/Plugins/RouteParameters.h b/Plugins/RouteParameters.h
index 46ffeda2d..d7028604f 100644
--- a/Plugins/RouteParameters.h
+++ b/Plugins/RouteParameters.h
@@ -23,14 +23,73 @@ or see http://www.gnu.org/licenses/agpl.txt.
#include
#include
-#include "../DataStructures/HashTable.h"
+
+#include
+
+#include "../DataStructures/Coordinate.h"
struct RouteParameters {
+ RouteParameters() : zoomLevel(18), printInstructions(false), geometry(true), compression(true), checkSum(-1) {}
+ short zoomLevel;
+ bool printInstructions;
+ bool geometry;
+ bool compression;
+ int checkSum;
+ std::string service;
+ std::string outputFormat;
+ std::string jsonpParameter;
+ std::string language;
std::vector hints;
- std::vector parameters;
- std::vector viaPoints;
- HashTable options;
+ std::vector<_Coordinate> coordinates;
typedef HashTable::MyIterator OptionsIterator;
+
+ void setZoomLevel(const short i) {
+ if (18 > i && 0 < i)
+ zoomLevel = i;
+ }
+
+ void setChecksum(const int c) {
+ checkSum = c;
+ }
+
+ void setInstructionFlag(const bool b) {
+ printInstructions = b;
+ }
+
+ void printService( const std::string & s) {
+ service = s;
+ }
+
+ void setOutputFormat(const std::string & s) {
+ outputFormat = s;
+ }
+
+ void setJSONpParameter(const std::string & s) {
+ jsonpParameter = s;
+ }
+
+ void addHint(const std::string & s) {
+ hints.push_back(s);
+ }
+
+ void setLanguage(const std::string & s) {
+ language = s;
+ }
+
+ void setGeometryFlag(const bool b) {
+ geometry = b;
+ }
+
+ void setCompressionFlag(const bool b) {
+ compression = b;
+ }
+
+ void addCoordinate(boost::fusion::vector < double, double > arg_) {
+ int lat = 100000.*boost::fusion::at_c < 0 > (arg_);
+ int lon = 100000.*boost::fusion::at_c < 1 > (arg_);
+ _Coordinate myCoordinate(lat, lon);
+ coordinates.push_back(_Coordinate(lat, lon));
+ }
};
diff --git a/Plugins/TimestampPlugin.h b/Plugins/TimestampPlugin.h
index f21201746..f2e8a4c2d 100644
--- a/Plugins/TimestampPlugin.h
+++ b/Plugins/TimestampPlugin.h
@@ -37,9 +37,8 @@ public:
std::string JSONParameter;
//json
- JSONParameter = routeParameters.options.Find("jsonp");
- if("" != JSONParameter) {
- reply.content += JSONParameter;
+ if("" != routeParameters.jsonpParameter) {
+ reply.content += routeParameters.jsonpParameter;
reply.content += "(";
}
diff --git a/Plugins/ViaRoutePlugin.h b/Plugins/ViaRoutePlugin.h
index cfdad4072..9b7695870 100644
--- a/Plugins/ViaRoutePlugin.h
+++ b/Plugins/ViaRoutePlugin.h
@@ -74,37 +74,21 @@ public:
std::string GetVersionString() const { return std::string("0.3 (DL)"); }
void HandleRequest(const RouteParameters & routeParameters, http::Reply& reply) {
//check number of parameters
- if( 2 > routeParameters.viaPoints.size() ) {
+ if( 2 > routeParameters.coordinates.size() ) {
reply = http::Reply::stockReply(http::Reply::badRequest);
return;
}
- unsigned zoomLevel = 18;
- if(routeParameters.options.Find("z") != ""){
- zoomLevel = atoi(routeParameters.options.Find("z").c_str());
- if(18 < zoomLevel)
- zoomLevel = 18;
- }
-
RawRouteData rawRoute;
rawRoute.checkSum = nodeHelpDesk->GetCheckSum();
- bool checksumOK = ((unsigned)atoi(routeParameters.options.Find("checksum").c_str()) == rawRoute.checkSum);
+ bool checksumOK = (routeParameters.checkSum == rawRoute.checkSum);
std::vector textCoord;
- for(unsigned i = 0; i < routeParameters.viaPoints.size(); ++i) {
- textCoord.resize(0);
- stringSplit (routeParameters.viaPoints[i], ',', textCoord);
- if(textCoord.size() != 2) {
+ for(unsigned i = 0; i < routeParameters.coordinates.size(); ++i) {
+ if(false == checkCoord(routeParameters.coordinates[i])) {
reply = http::Reply::stockReply(http::Reply::badRequest);
return;
}
- int vialat = static_cast(100000.*atof(textCoord[0].c_str()));
- int vialon = static_cast(100000.*atof(textCoord[1].c_str()));
- _Coordinate viaCoord(vialat, vialon);
- if(false == checkCoord(viaCoord)) {
- reply = http::Reply::stockReply(http::Reply::badRequest);
- return;
- }
- rawRoute.rawViaNodeCoordinates.push_back(viaCoord);
+ rawRoute.rawViaNodeCoordinates.push_back(routeParameters.coordinates[i]);
}
std::vector phantomNodeVector(rawRoute.rawViaNodeCoordinates.size());
for(unsigned i = 0; i < rawRoute.rawViaNodeCoordinates.size(); ++i) {
@@ -117,9 +101,8 @@ public:
}
}
// INFO("Brute force lookup of coordinate " << i);
- searchEngine->FindPhantomNodeForCoordinate( rawRoute.rawViaNodeCoordinates[i], phantomNodeVector[i], zoomLevel);
+ searchEngine->FindPhantomNodeForCoordinate( rawRoute.rawViaNodeCoordinates[i], phantomNodeVector[i], routeParameters.zoomLevel);
}
- //unsigned distance = 0;
for(unsigned i = 0; i < phantomNodeVector.size()-1; ++i) {
PhantomNodes segmentPhantomNodes;
@@ -143,24 +126,18 @@ public:
//TODO: Move to member as smart pointer
BaseDescriptor > > * desc;
- std::string JSONParameter = routeParameters.options.Find("jsonp");
- if("" != JSONParameter) {
- reply.content += JSONParameter;
+ if("" != routeParameters.jsonpParameter) {
+ reply.content += routeParameters.jsonpParameter;
reply.content += "(";
}
_DescriptorConfig descriptorConfig;
- unsigned descriptorType = descriptorTable[routeParameters.options.Find("output")];
- descriptorConfig.z = zoomLevel;
- if(routeParameters.options.Find("instructions") == "false") {
- descriptorConfig.instructions = false;
- }
- if(routeParameters.options.Find("geometry") == "false" ) {
- descriptorConfig.geometry = false;
- }
- if("cmp" == routeParameters.options.Find("no") || "cmp6" == routeParameters.options.Find("no") ) {
- descriptorConfig.encodeGeometry = false;
- }
+ unsigned descriptorType = descriptorTable[routeParameters.outputFormat];
+ descriptorConfig.z = routeParameters.zoomLevel;
+ descriptorConfig.instructions = routeParameters.printInstructions;
+ descriptorConfig.geometry = routeParameters.geometry;
+ descriptorConfig.encodeGeometry = routeParameters.compression;
+
switch(descriptorType){
case 0:
desc = new JSONDescriptor > >();
@@ -185,7 +162,7 @@ public:
desc->SetConfig(descriptorConfig);
desc->Run(reply, rawRoute, phantomNodes, *searchEngine);
- if("" != JSONParameter) {
+ if("" != routeParameters.jsonpParameter) {
reply.content += ")\n";
}
reply.headers.resize(3);
@@ -195,7 +172,7 @@ public:
reply.headers[0].value = tmp;
switch(descriptorType){
case 0:
- if("" != JSONParameter){
+ if("" != routeParameters.jsonpParameter){
reply.headers[1].name = "Content-Type";
reply.headers[1].value = "text/javascript";
reply.headers[2].name = "Content-Disposition";
@@ -216,7 +193,7 @@ public:
break;
default:
- if("" != JSONParameter){
+ if("" != routeParameters.jsonpParameter){
reply.headers[1].name = "Content-Type";
reply.headers[1].value = "text/javascript";
reply.headers[2].name = "Content-Disposition";
diff --git a/Server/APIGrammar.h b/Server/APIGrammar.h
new file mode 100644
index 000000000..df34ae267
--- /dev/null
+++ b/Server/APIGrammar.h
@@ -0,0 +1,59 @@
+/*
+ open source routing machine
+ Copyright (C) Dennis Luxen, others 2010
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU AFFERO General Public License as published by
+the Free Software Foundation; either version 3 of the License, or
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+or see http://www.gnu.org/licenses/agpl.txt.
+ */
+
+
+
+#ifndef APIGRAMMAR_H_
+#define APIGRAMMAR_H_
+
+#include
+#include
+#include
+
+namespace qi = boost::spirit::qi;
+
+template
+struct APIGrammar : qi::grammar {
+ APIGrammar(HandlerT * h) : APIGrammar::base_type(api_call), handler(h) {
+ api_call = qi::lit('/') >> string[boost::bind(&HandlerT::printService, handler, ::_1)] >> ('?') >> query;
+ query = (*(zoom | output | jsonp | checksum | location | hint | compressed_geometry | language | instruction) ) ;
+
+ zoom = (-qi::lit('&')) >> qi::lit('z') >> '=' >> qi::short_[boost::bind(&HandlerT::setZoomLevel, handler, ::_1)];
+ output = (-qi::lit('&')) >> qi::lit("output") >> '=' >> string[boost::bind(&HandlerT::setOutputFormat, handler, ::_1)];
+ jsonp = (-qi::lit('&')) >> qi::lit("jsonp") >> '=' >> stringwithDot[boost::bind(&HandlerT::setJSONpParameter, handler, ::_1)];
+ checksum = (-qi::lit('&')) >> qi::lit("checksum") >> '=' >> qi::int_[boost::bind(&HandlerT::setChecksum, handler, ::_1)];
+ instruction = (-qi::lit('&')) >> qi::lit("instructions") >> '=' >> qi::bool_[boost::bind(&HandlerT::setInstructionFlag, handler, ::_1)];
+ geometry = (-qi::lit('&')) >> qi::lit("geometry") >> '=' >> qi::bool_[boost::bind(&HandlerT::setGeometryFlag, handler, ::_1)];
+ cmp = (-qi::lit('&')) >> qi::lit("compression") >> '=' >> qi::bool_[boost::bind(&HandlerT::setCompressionFlag, handler, ::_1)];
+ location = (-qi::lit('&')) >> qi::lit("loc") >> '=' >> (qi::double_ >> qi::lit(',') >> qi::double_)[boost::bind(&HandlerT::addCoordinate, handler, ::_1)];
+ hint = (-qi::lit('&')) >> qi::lit("hint") >> '=' >> stringwithDot[boost::bind(&HandlerT::addHint, handler, ::_1)];
+ language = (-qi::lit('&')) >> qi::lit("hl") >> '=' >> string[boost::bind(&HandlerT::setLanguage, handler, ::_1)];
+
+ string = +(qi::char_("a-zA-Z"));
+ stringwithDot = +(qi::char_("a-zA-Z0-9_.-"));
+ }
+ qi::rule api_call, query;
+ qi::rule service, zoom, output, string, jsonp, checksum, location, hint, compressed_geometry, stringwithDot, language, instruction, geometry, cmp;
+
+ HandlerT * handler;
+};
+
+
+#endif /* APIGRAMMAR_H_ */
diff --git a/Server/RequestHandler.h b/Server/RequestHandler.h
index 92e664d23..35036a6ba 100644
--- a/Server/RequestHandler.h
+++ b/Server/RequestHandler.h
@@ -28,6 +28,7 @@ or see http://www.gnu.org/licenses/agpl.txt.
#include
#include
+#include "APIGrammar.h"
#include "BasicDatastructures.h"
#include "../DataStructures/HashTable.h"
#include "../Plugins/BasePlugin.h"
@@ -51,56 +52,45 @@ public:
void handle_request(const Request& req, Reply& rep){
//parse command
std::string request(req.uri);
- time_t ltime;
- struct tm *Tm;
- ltime=time(NULL);
- Tm=localtime(<ime);
+ { //This block logs the current request to std out. should be moved to a logging component
+ time_t ltime;
+ struct tm *Tm;
- INFO((Tm->tm_mday < 10 ? "0" : "" ) << Tm->tm_mday << "-" << (Tm->tm_mon+1 < 10 ? "0" : "" ) << (Tm->tm_mon+1) << "-" << 1900+Tm->tm_year << " " << (Tm->tm_hour < 10 ? "0" : "" ) << Tm->tm_hour << ":" << (Tm->tm_min < 10 ? "0" : "" ) << Tm->tm_min << ":" << (Tm->tm_sec < 10 ? "0" : "" ) << Tm->tm_sec << " " <<
- req.endpoint.to_string() << " " << req.referrer << ( 0 == req.referrer.length() ? "- " :" ") << req.agent << ( 0 == req.agent.length() ? "- " :" ") << request );
- std::size_t firstAmpPosition = request.find_first_of("?");
- //DEBUG("[debug] looking for handler for command: " << command);
+ ltime=time(NULL);
+ Tm=localtime(<ime);
+
+ INFO((Tm->tm_mday < 10 ? "0" : "" ) << Tm->tm_mday << "-" << (Tm->tm_mon+1 < 10 ? "0" : "" ) << (Tm->tm_mon+1) << "-" << 1900+Tm->tm_year << " " << (Tm->tm_hour < 10 ? "0" : "" ) << Tm->tm_hour << ":" << (Tm->tm_min < 10 ? "0" : "" ) << Tm->tm_min << ":" << (Tm->tm_sec < 10 ? "0" : "" ) << Tm->tm_sec << " " <<
+ req.endpoint.to_string() << " " << req.referrer << ( 0 == req.referrer.length() ? "- " :" ") << req.agent << ( 0 == req.agent.length() ? "- " :" ") << req.uri );
+ }
try {
- std::string command = request.substr(1,firstAmpPosition-1);
- if(pluginMap.Holds(command)) {
+ RouteParameters routeParameters;
+ APIGrammar apiParser(&routeParameters);
- RouteParameters routeParameters;
- std::stringstream ss(( firstAmpPosition == std::string::npos ? "" : request.substr(firstAmpPosition+1) ));
- std::string item;
- while(std::getline(ss, item, '&')) {
- size_t found = item.find('=');
- if(found == std::string::npos) {
- routeParameters.parameters.push_back(item);
- } else {
- std::string p = item.substr(0, found);
- std::transform(p.begin(), p.end(), p.begin(), (int(*)(int)) std::tolower);
- std::string o = item.substr(found+1);
- if("jsonp" != p && "hint" != p)
- std::transform(o.begin(), o.end(), o.begin(), (int(*)(int)) std::tolower);
- if("loc" == p) {
- if(25 >= routeParameters.viaPoints.size()) {
- routeParameters.viaPoints.push_back(o);
- }
- } else if("hint" == p) {
- routeParameters.hints.resize(routeParameters.viaPoints.size());
- if(routeParameters.viaPoints.size())
- routeParameters.hints.back() = o;
- } else {
- routeParameters.options.Set(p, o);
- }
- }
- }
- // std::cout << "[debug] found handler for '" << command << "' at version: " << pluginMap.Find(command)->GetVersionString() << std::endl;
- // std::cout << "[debug] remaining parameters: " << parameters.size() << std::endl;
- rep.status = Reply::ok;
- _pluginVector[pluginMap.Find(command)]->HandleRequest(routeParameters, rep );
-
- // std::cout << rep.content << std::endl;
+ std::string::iterator it = request.begin();
+ bool result = boost::spirit::qi::parse(it, request.end(), apiParser); // returns true if successful
+ if (!result || (it != request.end()) ) {
+ rep = http::Reply::stockReply(http::Reply::badRequest);
+ std::stringstream content;
+ int position = std::distance(request.begin(), it);
+ content << "Input seems to be malformed close to position " << position << "
";
+ content << "";
+ content << req.uri << "
";
+ for(unsigned i = 0, end = std::distance(request.begin(), it); i < end; ++i)
+ content << " ";
+ content << "^" << "
";
+ content << "
";
+ rep.content += content.str();
} else {
- rep = Reply::stockReply(Reply::badRequest);
+ //Finished parsing, lets call the right plugin to handle the request
+ if(pluginMap.Holds(routeParameters.service)) {
+ rep.status = Reply::ok;
+ _pluginVector[pluginMap.Find(routeParameters.service)]->HandleRequest(routeParameters, rep );
+ } else {
+ rep = Reply::stockReply(Reply::badRequest);
+ }
+ return;
}
- return;
} catch(std::exception& e) {
rep = Reply::stockReply(Reply::internalServerError);
std::cerr << "[server error] code: " << e.what() << ", uri: " << req.uri << std::endl;
@@ -112,7 +102,7 @@ public:
std::cout << "[handler] registering plugin " << plugin->GetDescriptor() << std::endl;
pluginMap.Add(plugin->GetDescriptor(), _pluginCount);
_pluginVector.push_back(plugin);
- _pluginCount++;
+ ++_pluginCount;
}
private: