diff options
| -rw-r--r-- | icespider/compile/routeCompiler.cpp | 2 | ||||
| -rw-r--r-- | icespider/core/core.cpp | 69 | ||||
| -rw-r--r-- | icespider/core/core.h | 28 | ||||
| -rw-r--r-- | icespider/core/ihttpRequest.cpp | 5 | ||||
| -rw-r--r-- | icespider/core/ihttpRequest.h | 10 | ||||
| -rw-r--r-- | icespider/core/irouteHandler.cpp | 9 | ||||
| -rw-r--r-- | icespider/core/irouteHandler.h | 10 | ||||
| -rw-r--r-- | icespider/core/paths.cpp | 47 | ||||
| -rw-r--r-- | icespider/core/paths.h | 45 | ||||
| -rw-r--r-- | icespider/unittests/testApp.cpp | 78 | ||||
| -rw-r--r-- | icespider/unittests/testCompile.cpp | 9 | ||||
| -rw-r--r-- | icespider/unittests/testRoutes.json | 2 | 
12 files changed, 295 insertions, 19 deletions
| diff --git a/icespider/compile/routeCompiler.cpp b/icespider/compile/routeCompiler.cpp index 1bf61a7..4881129 100644 --- a/icespider/compile/routeCompiler.cpp +++ b/icespider/compile/routeCompiler.cpp @@ -221,7 +221,7 @@ namespace IceSpider {  					fprintbf(4, output, "auto _p_%s(request->get%sParam<%s>(_pn_%s));\n",  									 p->name, getEnumString(p->source), Slice::typeToString(ip->type()), p->name);  				} -				fprintbf(4, output, "auto prx = getProxy<%s>();\n", proxyName); +				fprintbf(4, output, "auto prx = getProxy<%s>(request);\n", proxyName);  				if (o->returnsData()) {  					fprintbf(4, output, "request->response(prx->%s(", operation);  				} diff --git a/icespider/core/core.cpp b/icespider/core/core.cpp new file mode 100644 index 0000000..7c501c5 --- /dev/null +++ b/icespider/core/core.cpp @@ -0,0 +1,69 @@ +#include "core.h" +#include <boost/algorithm/string/split.hpp> +#include <boost/algorithm/string/classification.hpp> + +namespace ba = boost::algorithm; + +namespace IceSpider { +	Core::Core() +	{ +		// Big enough to map all the request methods +		routes.resize(UserIceSpider::HttpMethod::OPTIONS + 1); +		// Initialize routes +		for (const auto & rp : AdHoc::PluginManager::getDefault()->getAll<IRouteHandler>()) { +			auto r = rp->implementation(); +			auto & mroutes = routes[r->method]; +			if (mroutes.size() <= r->pathElementCount()) { +				mroutes.resize(r->pathElementCount() + 1); +			} +			mroutes[r->pathElementCount()].push_back(r); +		} +	} + +	Core::~Core() +	{ +	} + +	void +	Core::process(IHttpRequest * request) const +	{ +		auto routeHandler = findRoute(request); +		routeHandler->execute(request); +	} + +	const IRouteHandler * +	Core::findRoute(const IHttpRequest * request) const +	{ +		auto path = request->getRequestPath().substr(1); +		const auto & mroutes = routes[request->getRequestMethod()]; +		std::vector<std::string> pathparts; +		if (!path.empty()) { +			ba::split(pathparts, path, ba::is_any_of("/"), ba::token_compress_off); +		} +		if (pathparts.size() > mroutes.size()) { +			// Not found error +			return NULL; +		} +		const auto & routeSet = mroutes[pathparts.size()]; +		auto ri = std::find_if(routeSet.begin(), routeSet.end(), [&pathparts](const auto & r) { +			auto rpi = r->parts.begin(); +			for (auto ppi = pathparts.begin(); ppi != pathparts.end(); ++ppi, ++rpi) { +				if (!(*rpi)->matches(*ppi)) return false; +			} +			return true; +		}); +		if (ri == routeSet.end()) { +			// Not found error +			return NULL; +		} +		return (*ri); +	} + +	Ice::ObjectPrx +	Core::getProxy(const char * type) const +	{ +		fprintf(stderr, "request for proxy type %s\n", type); +		return NULL; +	} +} + diff --git a/icespider/core/core.h b/icespider/core/core.h new file mode 100644 index 0000000..afca336 --- /dev/null +++ b/icespider/core/core.h @@ -0,0 +1,28 @@ +#ifndef ICESPIDER_CORE_CORE_H +#define ICESPIDER_CORE_CORE_H + +#include <visibility.h> +#include <vector> +#include "irouteHandler.h" + +namespace IceSpider { +	class DLL_PUBLIC Core { +		public: +			typedef std::vector<const IRouteHandler *> Routes; +			typedef std::vector<Routes> LengthRoutes; +			typedef std::vector<LengthRoutes> MethodRoutes; + +			Core(); +			~Core(); + +			void process(IHttpRequest *) const; +			const IRouteHandler * findRoute(const IHttpRequest *) const; + +			Ice::ObjectPrx getProxy(const char * type) const; + +			MethodRoutes routes; +	}; +} + +#endif + diff --git a/icespider/core/ihttpRequest.cpp b/icespider/core/ihttpRequest.cpp index 423e439..0e14957 100644 --- a/icespider/core/ihttpRequest.cpp +++ b/icespider/core/ihttpRequest.cpp @@ -1,6 +1,11 @@  #include "ihttpRequest.h"  namespace IceSpider { +	IHttpRequest::IHttpRequest(const Core * c) : +		core(c) +	{ +	} +  	Ice::Context  	IHttpRequest::getContext() const  	{ diff --git a/icespider/core/ihttpRequest.h b/icespider/core/ihttpRequest.h index 3ea877e..2193a67 100644 --- a/icespider/core/ihttpRequest.h +++ b/icespider/core/ihttpRequest.h @@ -5,11 +5,19 @@  #include <IceUtil/Optional.h>  #include <Ice/Current.h>  #include <visibility.h> +#include <routes.h>  namespace IceSpider { +	class Core; +  	class DLL_PUBLIC IHttpRequest {  		public: +			IHttpRequest(const Core *); +  			Ice::Context getContext() const; +			virtual std::string getRequestPath() const = 0; +			virtual UserIceSpider::HttpMethod getRequestMethod() const = 0; +  			template<typename T>  			T getURLParam(const std::string & key) const { (void)key; return T(); }  			template<typename T> @@ -20,6 +28,8 @@ namespace IceSpider {  			T getHeaderParam(const std::string & key) const { (void)key; return T(); }  			template<typename T>  			void response(const T &) const { } + +			const Core * core;  	};  } diff --git a/icespider/core/irouteHandler.cpp b/icespider/core/irouteHandler.cpp index 2107ff7..3007772 100644 --- a/icespider/core/irouteHandler.cpp +++ b/icespider/core/irouteHandler.cpp @@ -1,19 +1,20 @@  #include "irouteHandler.h" +#include "core.h"  #include <plugins.impl.h>  INSTANTIATEPLUGINOF(IceSpider::IRouteHandler);  namespace IceSpider {  	IRouteHandler::IRouteHandler(UserIceSpider::HttpMethod m, const std::string & p) : -		method(m), -		path(p) +		Path(p), +		method(m)  	{  	}  	Ice::ObjectPrx -	IRouteHandler::getProxy(const char *) const +	IRouteHandler::getProxy(IHttpRequest * request, const char * type) const  	{ -		return NULL; +		return request->core->getProxy(type);  	}  } diff --git a/icespider/core/irouteHandler.h b/icespider/core/irouteHandler.h index e02d0a3..416048e 100644 --- a/icespider/core/irouteHandler.h +++ b/icespider/core/irouteHandler.h @@ -2,26 +2,26 @@  #define ICESPIDER_IROUTEHANDLER_H  #include "ihttpRequest.h" +#include "paths.h"  #include <routes.h>  #include <plugins.h>  #include <visibility.h>  namespace IceSpider { -	class DLL_PUBLIC IRouteHandler : public AdHoc::AbstractPluginImplementation { +	class DLL_PUBLIC IRouteHandler : public AdHoc::AbstractPluginImplementation, public Path {  		public:  			IRouteHandler(UserIceSpider::HttpMethod, const std::string & path);  			virtual void execute(IHttpRequest * request) const = 0;  			const UserIceSpider::HttpMethod method; -			const std::string path;  		protected: -			Ice::ObjectPrx getProxy(const char *) const; +			Ice::ObjectPrx getProxy(IHttpRequest *, const char *) const;  			template<typename Interface> -			typename Interface::ProxyType getProxy() const +			typename Interface::ProxyType getProxy(IHttpRequest * request) const  			{ -				return Interface::ProxyType::uncheckedCast(getProxy(typeid(Interface).name())); +				return Interface::ProxyType::uncheckedCast(getProxy(request, typeid(Interface).name()));  			}  	};  	typedef AdHoc::PluginOf<IRouteHandler> RouteHandlers; diff --git a/icespider/core/paths.cpp b/icespider/core/paths.cpp new file mode 100644 index 0000000..f4bad0e --- /dev/null +++ b/icespider/core/paths.cpp @@ -0,0 +1,47 @@ +#include "paths.h" +#include <boost/algorithm/string/split.hpp> + +namespace ba = boost::algorithm; + +namespace IceSpider { +	Path::Path(const std::string & p) : +		path(p) +	{ +		auto relp = p.substr(1); +		if (relp.empty()) return; +		for (auto pi = ba::make_split_iterator(relp, ba::first_finder("/", ba::is_equal())); pi != decltype(pi)(); ++pi) { +			std::string pp(pi->begin(), pi->end()); +			if (pp.front() == '{' && pp.back() == '}') { +				parts.push_back(PathPartPtr(new PathParameter())); +			} +			else { +				parts.push_back(PathPartPtr(new PathLiteral(pp))); +			} +		} +	} + +	unsigned int +	Path::pathElementCount() const +	{ +		return parts.size(); +	} + +	PathLiteral::PathLiteral(const std::string & p) : +		value(p) +	{ +		 +	} + +	bool +	PathLiteral::matches(const std::string & v) const +	{ +		return value == v; +	} + +	bool +	PathParameter::matches(const std::string &) const +	{ +		return true; +	} +} + diff --git a/icespider/core/paths.h b/icespider/core/paths.h new file mode 100644 index 0000000..0999593 --- /dev/null +++ b/icespider/core/paths.h @@ -0,0 +1,45 @@ +#ifndef ICESPIDER_CORE_PATHS_H +#define ICESPIDER_CORE_PATHS_H + +#include <vector> +#include <string> +#include <memory> + +namespace IceSpider { + +	class PathPart { +		public: +			virtual bool matches(const std::string &) const = 0; +	}; +	typedef std::shared_ptr<PathPart> PathPartPtr; + +	class PathLiteral : public PathPart { +		public: +			PathLiteral(const std::string & v); + +			bool matches(const std::string &) const; + +		private: +			const std::string value; +	}; + +	class PathParameter : public PathPart { +		public: +			bool matches(const std::string &) const; +	}; +	class Path { +		public: +			typedef std::vector<PathPartPtr> PathParts; + +			Path(const std::string &); + +			const std::string path; + +			unsigned int pathElementCount() const; + +			PathParts parts; +	}; +} + +#endif + diff --git a/icespider/unittests/testApp.cpp b/icespider/unittests/testApp.cpp index 01249b7..2c4e1b2 100644 --- a/icespider/unittests/testApp.cpp +++ b/icespider/unittests/testApp.cpp @@ -3,9 +3,87 @@  #include <plugins.h>  #include <irouteHandler.h> +#include <core.h> + +using namespace UserIceSpider;  BOOST_AUTO_TEST_CASE( testLoadConfiguration )  {  	BOOST_REQUIRE_EQUAL(4, AdHoc::PluginManager::getDefault()->getAll<IceSpider::IRouteHandler>().size());  } +BOOST_FIXTURE_TEST_SUITE(c, IceSpider::Core); + +BOOST_AUTO_TEST_CASE( testCoreSettings ) +{ +	BOOST_REQUIRE_EQUAL(6, routes.size()); +	BOOST_REQUIRE_EQUAL(4, routes[HttpMethod::GET].size()); +	BOOST_REQUIRE_EQUAL(1, routes[HttpMethod::GET][0].size()); +	BOOST_REQUIRE_EQUAL(0, routes[HttpMethod::GET][1].size()); +	BOOST_REQUIRE_EQUAL(0, routes[HttpMethod::GET][2].size()); +	BOOST_REQUIRE_EQUAL(1, routes[HttpMethod::GET][3].size()); +	BOOST_REQUIRE_EQUAL(0, routes[HttpMethod::HEAD].size()); +	BOOST_REQUIRE_EQUAL(2, routes[HttpMethod::POST].size()); +	BOOST_REQUIRE_EQUAL(0, routes[HttpMethod::POST][0].size()); +	BOOST_REQUIRE_EQUAL(1, routes[HttpMethod::POST][1].size()); +	BOOST_REQUIRE_EQUAL(0, routes[HttpMethod::PUT].size()); +	BOOST_REQUIRE_EQUAL(2, routes[HttpMethod::DELETE].size()); +	BOOST_REQUIRE_EQUAL(0, routes[HttpMethod::DELETE][0].size()); +	BOOST_REQUIRE_EQUAL(1, routes[HttpMethod::DELETE][1].size()); +	BOOST_REQUIRE_EQUAL(0, routes[HttpMethod::OPTIONS].size()); +} + +class TestRequest : public IceSpider::IHttpRequest { +	public: +		TestRequest(const IceSpider::Core * c, HttpMethod m, const std::string & p) : +			IHttpRequest(c), +			method(m), +			path(p) +		{ +		} +			 +		std::string getRequestPath() const override +		{ +			return path; +		} + +		HttpMethod getRequestMethod() const override +		{ +			return method; +		} + +		const HttpMethod method; +		const std::string path; +}; + +BOOST_AUTO_TEST_CASE( testFindRoutes ) +{ +	TestRequest requestGetIndex(this, HttpMethod::GET, "/"); +	BOOST_REQUIRE(findRoute(&requestGetIndex)); + +	TestRequest requestPostIndex(this, HttpMethod::POST, "/"); +	BOOST_REQUIRE(!findRoute(&requestPostIndex)); + +	TestRequest requestPostUpdate(this, HttpMethod::POST, "/something"); +	BOOST_REQUIRE(findRoute(&requestPostUpdate)); + +	TestRequest requestGetUpdate(this, HttpMethod::GET, "/something"); +	BOOST_REQUIRE(!findRoute(&requestGetUpdate)); + +	TestRequest requestGetItem(this, HttpMethod::GET, "/view/something/something"); +	BOOST_REQUIRE(findRoute(&requestGetItem)); + +	TestRequest requestGetItemLong(this, HttpMethod::GET, "/view/something/something/extra"); +	BOOST_REQUIRE(!findRoute(&requestGetItemLong)); + +	TestRequest requestGetItemShort(this, HttpMethod::GET, "/view/missingSomething"); +	BOOST_REQUIRE(!findRoute(&requestGetItemShort)); + +	TestRequest requestGetNothing(this, HttpMethod::GET, "/badview/something/something"); +	BOOST_REQUIRE(!findRoute(&requestGetNothing)); + +	TestRequest requestDeleteThing(this, HttpMethod::DELETE, "/something"); +	BOOST_REQUIRE(findRoute(&requestDeleteThing)); +} + +BOOST_AUTO_TEST_SUITE_END(); diff --git a/icespider/unittests/testCompile.cpp b/icespider/unittests/testCompile.cpp index d46a33d..b7ce0f5 100644 --- a/icespider/unittests/testCompile.cpp +++ b/icespider/unittests/testCompile.cpp @@ -37,7 +37,7 @@ BOOST_AUTO_TEST_CASE( testLoadConfiguration )  	BOOST_REQUIRE_EQUAL(0, cfg->routes[0]->params.size());  	BOOST_REQUIRE_EQUAL("item", cfg->routes[1]->name); -	BOOST_REQUIRE_EQUAL("/{s}/{i}", cfg->routes[1]->path); +	BOOST_REQUIRE_EQUAL("/view/{s}/{i}", cfg->routes[1]->path);  	BOOST_REQUIRE_EQUAL(2, cfg->routes[1]->params.size());  	BOOST_REQUIRE_EQUAL("del", cfg->routes[2]->name); @@ -77,10 +77,6 @@ BOOST_AUTO_TEST_CASE( testCompile )  	BOOST_REQUIRE_EQUAL(0, compileResult);  } -class DuffRequest : public IceSpider::IHttpRequest { - -}; -  BOOST_AUTO_TEST_CASE( testLoad )  {  	auto outputso = binDir / "testRoutes.so"; @@ -93,9 +89,6 @@ BOOST_AUTO_TEST_CASE( testLoad )  	{  		auto route = AdHoc::PluginManager::getDefault()->get<IceSpider::IRouteHandler>("common::index");  		BOOST_REQUIRE(route); -		BOOST_REQUIRE_THROW({ -			route->implementation()->execute(new DuffRequest()); -		}, IceUtil::NullHandleException);  	}  	BOOST_REQUIRE_EQUAL(0, dlclose(lib)); diff --git a/icespider/unittests/testRoutes.json b/icespider/unittests/testRoutes.json index b4eb54f..2b7b48d 100644 --- a/icespider/unittests/testRoutes.json +++ b/icespider/unittests/testRoutes.json @@ -9,7 +9,7 @@  	},  	{  		"name": "item", -		"path": "/{s}/{i}", +		"path": "/view/{s}/{i}",  		"method": "GET",  		"operation": "TestIceSpider.TestApi.withParams"  	}, | 
