diff options
| -rw-r--r-- | icespider/compile/routeCompiler.cpp | 2 | ||||
| -rw-r--r-- | icespider/core/acceptable.cpp | 12 | ||||
| -rw-r--r-- | icespider/core/acceptable.h | 18 | ||||
| -rw-r--r-- | icespider/core/core.cpp | 1 | ||||
| -rw-r--r-- | icespider/core/ihttpRequest.cpp | 35 | ||||
| -rw-r--r-- | icespider/core/ihttpRequest.h | 17 | ||||
| -rw-r--r-- | icespider/core/irouteHandler.cpp | 28 | ||||
| -rw-r--r-- | icespider/core/irouteHandler.h | 9 | ||||
| -rw-r--r-- | icespider/unittests/Jamfile.jam | 2 | ||||
| -rw-r--r-- | icespider/unittests/testApp.cpp | 18 | 
10 files changed, 131 insertions, 11 deletions
| diff --git a/icespider/compile/routeCompiler.cpp b/icespider/compile/routeCompiler.cpp index 6f5ded0..c190a86 100644 --- a/icespider/compile/routeCompiler.cpp +++ b/icespider/compile/routeCompiler.cpp @@ -277,7 +277,7 @@ namespace IceSpider {  				}  				fprintbf(4, output, "auto prx = getProxy<%s>(request);\n", proxyName);  				if (o->returnsData()) { -					fprintbf(4, output, "request->response(prx->%s(", operation); +					fprintbf(4, output, "request->response(this, prx->%s(", operation);  				}  				else {  					fprintbf(4, output, "prx->%s(", operation); diff --git a/icespider/core/acceptable.cpp b/icespider/core/acceptable.cpp new file mode 100644 index 0000000..d7a2c58 --- /dev/null +++ b/icespider/core/acceptable.cpp @@ -0,0 +1,12 @@ +#include "acceptable.h" +#include <stdlib.h> +#include <string.h> + +namespace IceSpider { +	void +	Acceptable::free() +	{ +		::free(grp); +		::free(type); +	} +} diff --git a/icespider/core/acceptable.h b/icespider/core/acceptable.h new file mode 100644 index 0000000..20b6f09 --- /dev/null +++ b/icespider/core/acceptable.h @@ -0,0 +1,18 @@ +#ifndef ICESPIDER_ACCEPTABLE_H +#define ICESPIDER_ACCEPTABLE_H + +#include <visibility.h> + +namespace IceSpider { +	class DLL_PUBLIC Acceptable { +		public: +			void free(); + +			char * grp; +			char * type; +			float pri; +	}; +} + +#endif + diff --git a/icespider/core/core.cpp b/icespider/core/core.cpp index b21a805..85a9bfa 100644 --- a/icespider/core/core.cpp +++ b/icespider/core/core.cpp @@ -12,6 +12,7 @@ namespace IceSpider {  		// Initialize routes  		for (const auto & rp : AdHoc::PluginManager::getDefault()->getAll<IRouteHandler>()) {  			auto r = rp->implementation(); +			r->initialize();  			auto & mroutes = routes[r->method];  			if (mroutes.size() <= r->pathElementCount()) {  				mroutes.resize(r->pathElementCount() + 1); diff --git a/icespider/core/ihttpRequest.cpp b/icespider/core/ihttpRequest.cpp index a255de0..8e9b8f4 100644 --- a/icespider/core/ihttpRequest.cpp +++ b/icespider/core/ihttpRequest.cpp @@ -1,4 +1,5 @@  #include "ihttpRequest.h" +#include "irouteHandler.h"  #include "util.h"  #include <boost/lexical_cast.hpp> @@ -24,10 +25,38 @@ namespace IceSpider {  	}  	Slicer::SerializerPtr -	IHttpRequest::getSerializer() const +	IHttpRequest::getSerializer(const IRouteHandler * handler) const  	{ -		return Slicer::StreamSerializerFactory::createNew( -			"application/json", getOutputStream()); +		auto acceptHdr = getHeaderParam("Accept"); +		if (acceptHdr) { +			auto accept = acceptHdr->c_str(); +			std::vector<Acceptable> accepts; +			accepts.reserve(5); +			char * grp = NULL, * type = NULL; +			float pri = 0.0f; +			int chars, v; +			while ((v = sscanf(accept, " %m[^/] / %m[^;,] %n ; q = %f , %n", &grp, &type, &chars, &pri, &chars)) >= 2) { +				accepts.push_back( { grp, type, (v < 3 ? 1.0f : pri) } ); +				grp = NULL; +				type = NULL; +				accept += chars; +			} +			free(grp); +			free(type); +			std::stable_sort(accepts.begin(), accepts.end(), [](const auto & a, const auto & b) { return a.pri < b.pri; }); +			Slicer::SerializerPtr serializer; +			auto & strm = getOutputStream(); +			for(auto & a : accepts) { +				if (!serializer) { +					serializer = handler->getSerializer(a.grp, a.type, strm); +				} +				a.free(); +			} +			return serializer; +		} +		else { +			return handler->defaultSerializer(getOutputStream()); +		}  	}  	const std::string & diff --git a/icespider/core/ihttpRequest.h b/icespider/core/ihttpRequest.h index cdc2161..45bcd11 100644 --- a/icespider/core/ihttpRequest.h +++ b/icespider/core/ihttpRequest.h @@ -8,9 +8,11 @@  #include <routes.h>  #include <slicer/slicer.h>  #include <IceUtil/Optional.h> +#include "acceptable.h"  namespace IceSpider {  	class Core; +	class IRouteHandler;  	typedef std::vector<std::string> PathElements;  	typedef IceUtil::Optional<std::string> OptionalString; @@ -27,7 +29,7 @@ namespace IceSpider {  			virtual OptionalString getQueryStringParam(const std::string &) const = 0;  			virtual OptionalString getHeaderParam(const std::string &) const = 0;  			virtual Slicer::DeserializerPtr getDeserializer() const; -			virtual Slicer::SerializerPtr getSerializer() const; +			virtual Slicer::SerializerPtr getSerializer(const IRouteHandler *) const;  			virtual std::istream & getInputStream() const = 0;  			virtual std::ostream & getOutputStream() const = 0; @@ -44,11 +46,16 @@ namespace IceSpider {  			IceUtil::Optional<T> getHeaderParam(const std::string & key) const;  			void response(short, const std::string &) const;  			template<typename T> -			void response(const T & t) const +			void response(const IRouteHandler * route, const T & t) const  			{ -				auto s = getSerializer(); -				response(200, "OK"); -				Slicer::SerializeAnyWith<T>(t, s); +				auto s = getSerializer(route); +				if (s) { +					response(200, "OK"); +					Slicer::SerializeAnyWith<T>(t, s); +				} +				else { +					response(406, "Unacceptable"); +				}  			}  			const Core * core; diff --git a/icespider/core/irouteHandler.cpp b/icespider/core/irouteHandler.cpp index 4d78397..11d18e8 100644 --- a/icespider/core/irouteHandler.cpp +++ b/icespider/core/irouteHandler.cpp @@ -11,10 +11,38 @@ namespace IceSpider {  	{  	} +	void +	IRouteHandler::initialize() +	{ +		auto globalSerializers = AdHoc::PluginManager::getDefault()->getAll<Slicer::StreamSerializerFactory>(); +		for (const auto & gs : globalSerializers) { +			auto slash = gs->name.find('/'); +			routeSerializers.insert({ { gs->name.substr(0, slash), gs->name.substr(slash + 1) }, gs }); +		} +	} +  	Ice::ObjectPrx  	IRouteHandler::getProxy(IHttpRequest * request, const char * type) const  	{  		return request->core->getProxy(type);  	} + +	Slicer::SerializerPtr +	IRouteHandler::getSerializer(const char * grp, const char * type, std::ostream & strm) const +	{ +		for (const auto & rs : routeSerializers) { +			if ((!grp || rs.first.first == grp) && (!type || rs.first.second == type)) { +				return rs.second->implementation()->create(strm); +			} +		} +		return nullptr; +	} + +	Slicer::SerializerPtr +	IRouteHandler::defaultSerializer(std::ostream & strm) const +	{ +		return Slicer::StreamSerializerFactory::createNew( +			"application/json", strm); +	}  } diff --git a/icespider/core/irouteHandler.h b/icespider/core/irouteHandler.h index 1334bee..0417775 100644 --- a/icespider/core/irouteHandler.h +++ b/icespider/core/irouteHandler.h @@ -13,11 +13,20 @@ namespace IceSpider {  	class DLL_PUBLIC IRouteHandler : public AdHoc::AbstractPluginImplementation, public Path {  		public:  			IRouteHandler(HttpMethod, const std::string & path); +  			virtual void execute(IHttpRequest * request) const = 0; +			virtual void initialize(); +			virtual Slicer::SerializerPtr getSerializer(const char *, const char *, std::ostream &) const; +			virtual Slicer::SerializerPtr defaultSerializer(std::ostream &) const;  			const HttpMethod method;  		protected: +			typedef boost::shared_ptr<const AdHoc::PluginOf<Slicer::StreamSerializerFactory>> StreamSerializerFactoryPtr; +			typedef std::pair<std::string, std::string> ContentType; +			typedef std::map<ContentType, StreamSerializerFactoryPtr> RouteSerializers; +			RouteSerializers routeSerializers; +  			template <typename T, typename K>  			inline T requiredParameterNotFound(const char *, const K & key) const  			{ diff --git a/icespider/unittests/Jamfile.jam b/icespider/unittests/Jamfile.jam index a10d718..234e715 100644 --- a/icespider/unittests/Jamfile.jam +++ b/icespider/unittests/Jamfile.jam @@ -20,6 +20,7 @@ actions routes2cpp bind ICESPIDER  lib adhocutil : : : : <include>/usr/include/adhocutil ;  lib slicer : : : : <include>/usr/include/slicer ;  lib slicer-json : : : : <include>/usr/include/slicer ; +lib slicer-xml : : : : <include>/usr/include/slicer ;  lib boost_utf : : <name>boost_unit_test_framework ;  lib dl ;  path-constant me : . ; @@ -63,6 +64,7 @@ run  	<library>adhocutil  	<library>slicer  	<library>slicer-json +	<library>slicer-xml  	<library>../common//icespider-common  	<library>../core//icespider-core  	<implicit-dependency>../common//icespider-common diff --git a/icespider/unittests/testApp.cpp b/icespider/unittests/testApp.cpp index 80dd6c1..1031eaf 100644 --- a/icespider/unittests/testApp.cpp +++ b/icespider/unittests/testApp.cpp @@ -68,7 +68,7 @@ class TestRequest : public IHttpRequest {  		IceUtil::Optional<std::string> getHeaderParam(const std::string & key) const override  		{ -			return AdHoc::safeMapLookup<std::runtime_error>(hdr, key); +			return hdr.find(key) == hdr.end() ? IceUtil::Optional<std::string>() : hdr.find(key)->second;  		}  		std::istream & getInputStream() const override @@ -161,7 +161,6 @@ BOOST_AUTO_TEST_CASE( testCallMethods )  	auto adp = communicator->createObjectAdapterWithEndpoints("test", "default");  	auto obj = adp->addWithUUID(new TestSerice());  	adp->activate(); -	fprintf(stderr, "%s\n", obj->ice_id().c_str());  	communicator->getProperties()->setProperty("TestIceSpider::TestApi", communicator->proxyToString(obj));  	TestRequest requestGetIndex(this, HttpMethod::GET, "/"); @@ -190,6 +189,21 @@ BOOST_AUTO_TEST_CASE( testCallMethods )  	process(&requestUpdateItem);  	BOOST_REQUIRE_EQUAL(requestDeleteItem.output.str(), "Status: 200 OK\r\n\r\n"); +	TestRequest requestJson(this, HttpMethod::GET, "/"); +	requestJson.hdr["Accept"] = "application/json"; +	process(&requestJson); +	BOOST_REQUIRE_EQUAL(requestJson.output.str(), "Status: 200 OK\r\n\r\n{\"value\":\"index\"}"); + +	TestRequest requestXml(this, HttpMethod::GET, "/"); +	requestXml.hdr["Accept"] = "application/xml"; +	process(&requestXml); +	BOOST_REQUIRE_EQUAL(requestXml.output.str(), "Status: 200 OK\r\n\r\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<SomeModel><value>index</value></SomeModel>\n"); + +	TestRequest requestBadAccept(this, HttpMethod::GET, "/"); +	requestBadAccept.hdr["Accept"] = "not/supported"; +	process(&requestBadAccept); +	BOOST_REQUIRE_EQUAL(requestBadAccept.output.str(), "Status: 406 Unacceptable\r\n\r\n"); +  	adp->deactivate();  } | 
