summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--icespider/compile/routeCompiler.cpp2
-rw-r--r--icespider/core/acceptable.cpp12
-rw-r--r--icespider/core/acceptable.h18
-rw-r--r--icespider/core/core.cpp1
-rw-r--r--icespider/core/ihttpRequest.cpp35
-rw-r--r--icespider/core/ihttpRequest.h17
-rw-r--r--icespider/core/irouteHandler.cpp28
-rw-r--r--icespider/core/irouteHandler.h9
-rw-r--r--icespider/unittests/Jamfile.jam2
-rw-r--r--icespider/unittests/testApp.cpp18
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();
}