summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--icespider/common/http.ice11
-rw-r--r--icespider/core/acceptable.cpp12
-rw-r--r--icespider/core/acceptable.h18
-rw-r--r--icespider/core/ihttpRequest.cpp40
-rw-r--r--icespider/core/ihttpRequest.h9
-rw-r--r--icespider/core/irouteHandler.cpp22
-rw-r--r--icespider/core/irouteHandler.h11
-rw-r--r--icespider/unittests/testApp.cpp10
8 files changed, 60 insertions, 73 deletions
diff --git a/icespider/common/http.ice b/icespider/common/http.ice
index 33c0543..cefb494 100644
--- a/icespider/common/http.ice
+++ b/icespider/common/http.ice
@@ -9,6 +9,17 @@ module IceSpider {
enum ParameterSource {
URL, Body, QueryString, Header
};
+
+ struct MimeType {
+ string group;
+ string type;
+ };
+
+ class Accept {
+ optional(0) string group;
+ optional(1) string type;
+ float q = 1.0;
+ };
};
#endif
diff --git a/icespider/core/acceptable.cpp b/icespider/core/acceptable.cpp
deleted file mode 100644
index d7a2c58..0000000
--- a/icespider/core/acceptable.cpp
+++ /dev/null
@@ -1,12 +0,0 @@
-#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
deleted file mode 100644
index 20b6f09..0000000
--- a/icespider/core/acceptable.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#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/ihttpRequest.cpp b/icespider/core/ihttpRequest.cpp
index a4e25b2..9b62507 100644
--- a/icespider/core/ihttpRequest.cpp
+++ b/icespider/core/ihttpRequest.cpp
@@ -24,48 +24,42 @@ namespace IceSpider {
}, getInputStream());
}
- Slicer::SerializerPtr
+ ContentTypeSerializer
IHttpRequest::getSerializer(const IRouteHandler * handler) const
{
auto acceptHdr = getHeaderParam("Accept");
if (acceptHdr) {
auto accept = acceptHdr->c_str();
- std::vector<Acceptable> accepts;
+ std::vector<AcceptPtr> accepts;
accepts.reserve(5);
- char * grp = NULL, * type = NULL;
+ char grp[BUFSIZ], type[BUFSIZ];
float pri = 0.0f;
int chars, v;
- while ((v = sscanf(accept, " %m[^ /] / %m[^ ;,] %n , %n", &grp, &type, &chars, &chars)) == 2) {
+ while ((v = sscanf(accept, " %[^ /] / %[^ ;,] %n , %n", grp, type, &chars, &chars)) == 2) {
accept += chars;
chars = 0;
- if ((v = sscanf(accept, " ; q = %f %n , %n", &pri, &chars, &chars)) != 1) {
- pri = 1.0;
+ auto a = new Accept();
+ if ((v = sscanf(accept, " ; q = %f %n , %n", &pri, &chars, &chars)) == 1) {
+ a->q = pri;
}
- if (!strcmp(grp, "*")) {
- free(grp);
- grp = NULL;
+ if (strcmp(grp, "*")) {
+ a->group = grp;
}
- if (!strcmp(type, "*")) {
- free(type);
- type = NULL;
+ if (strcmp(type, "*")) {
+ a->type = type;
}
- accepts.push_back( { grp, type, pri } );
- grp = NULL;
- type = NULL;
accept += chars;
+ accepts.push_back(a);
}
- 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;
+ std::stable_sort(accepts.begin(), accepts.end(), [](const auto & a, const auto & b) { return a->q > b->q; });
auto & strm = getOutputStream();
for(auto & a : accepts) {
- if (!serializer) {
- serializer = handler->getSerializer(a.grp, a.type, strm);
+ ContentTypeSerializer serializer = handler->getSerializer(a, strm);
+ if (serializer.second) {
+ return serializer;
}
- a.free();
}
- return serializer;
+ return ContentTypeSerializer();
}
else {
return handler->defaultSerializer(getOutputStream());
diff --git a/icespider/core/ihttpRequest.h b/icespider/core/ihttpRequest.h
index 45bcd11..9ce869f 100644
--- a/icespider/core/ihttpRequest.h
+++ b/icespider/core/ihttpRequest.h
@@ -8,7 +8,6 @@
#include <routes.h>
#include <slicer/slicer.h>
#include <IceUtil/Optional.h>
-#include "acceptable.h"
namespace IceSpider {
class Core;
@@ -16,6 +15,7 @@ namespace IceSpider {
typedef std::vector<std::string> PathElements;
typedef IceUtil::Optional<std::string> OptionalString;
+ typedef std::pair<MimeType, Slicer::SerializerPtr> ContentTypeSerializer;
class DLL_PUBLIC IHttpRequest {
public:
@@ -29,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 IRouteHandler *) const;
+ virtual ContentTypeSerializer getSerializer(const IRouteHandler *) const;
virtual std::istream & getInputStream() const = 0;
virtual std::ostream & getOutputStream() const = 0;
@@ -49,9 +49,10 @@ namespace IceSpider {
void response(const IRouteHandler * route, const T & t) const
{
auto s = getSerializer(route);
- if (s) {
+ if (s.second) {
+ getOutputStream() << "Content-Type: " << s.first.group << "/" << s.first.type << "\r\n";
response(200, "OK");
- Slicer::SerializeAnyWith<T>(t, s);
+ Slicer::SerializeAnyWith<T>(t, s.second);
}
else {
response(406, "Unacceptable");
diff --git a/icespider/core/irouteHandler.cpp b/icespider/core/irouteHandler.cpp
index a0d8fcd..82c6df1 100644
--- a/icespider/core/irouteHandler.cpp
+++ b/icespider/core/irouteHandler.cpp
@@ -26,32 +26,34 @@ namespace IceSpider {
return request->core->getProxy(type);
}
- Slicer::SerializerPtr
- IRouteHandler::getSerializer(const char * grp, const char * type, std::ostream & strm) const
+ ContentTypeSerializer
+ IRouteHandler::getSerializer(const AcceptPtr & a, std::ostream & strm) const
{
for (const auto & rs : routeSerializers) {
- if ((!grp || rs.first.first == grp) && (!type || rs.first.second == type)) {
- return rs.second->create(strm);
+ if ((!a->group || rs.first.group == a->group) && (!a->type || rs.first.type == a->type)) {
+ return { rs.first, rs.second->create(strm) };
}
}
- return nullptr;
+ return ContentTypeSerializer();
}
- Slicer::SerializerPtr
+ ContentTypeSerializer
IRouteHandler::defaultSerializer(std::ostream & strm) const
{
- return Slicer::StreamSerializerFactory::createNew(
- "application/json", strm);
+ return {
+ { "application", "json" },
+ Slicer::StreamSerializerFactory::createNew("application/json", strm)
+ };
}
void
- IRouteHandler::addRouteSerializer(const ContentType & ct, StreamSerializerFactoryPtr ssfp)
+ IRouteHandler::addRouteSerializer(const MimeType & ct, StreamSerializerFactoryPtr ssfp)
{
routeSerializers.insert({ ct, ssfp });
}
void
- IRouteHandler::removeRouteSerializer(const ContentType & ct)
+ IRouteHandler::removeRouteSerializer(const MimeType & ct)
{
auto i = routeSerializers.find(ct);
if (i != routeSerializers.end()) {
diff --git a/icespider/core/irouteHandler.h b/icespider/core/irouteHandler.h
index 1cfa5ee..bbd9ab3 100644
--- a/icespider/core/irouteHandler.h
+++ b/icespider/core/irouteHandler.h
@@ -16,15 +16,14 @@ namespace IceSpider {
virtual ~IRouteHandler();
virtual void execute(IHttpRequest * request) const = 0;
- virtual Slicer::SerializerPtr getSerializer(const char *, const char *, std::ostream &) const;
- virtual Slicer::SerializerPtr defaultSerializer(std::ostream &) const;
+ virtual ContentTypeSerializer getSerializer(const AcceptPtr &, std::ostream &) const;
+ virtual ContentTypeSerializer defaultSerializer(std::ostream &) const;
const HttpMethod method;
protected:
typedef Slicer::StreamSerializerFactory * StreamSerializerFactoryPtr;
- typedef std::pair<std::string, std::string> ContentType;
- typedef std::map<ContentType, StreamSerializerFactoryPtr> RouteSerializers;
+ typedef std::map<MimeType, StreamSerializerFactoryPtr> RouteSerializers;
RouteSerializers routeSerializers;
template <typename T, typename K>
@@ -42,8 +41,8 @@ namespace IceSpider {
return Interface::ProxyType::uncheckedCast(getProxy(request, typeid(Interface).name()));
}
- void addRouteSerializer(const ContentType &, StreamSerializerFactoryPtr);
- void removeRouteSerializer(const ContentType &);
+ void addRouteSerializer(const MimeType &, StreamSerializerFactoryPtr);
+ void removeRouteSerializer(const MimeType &);
};
typedef AdHoc::PluginOf<IRouteHandler> RouteHandlers;
}
diff --git a/icespider/unittests/testApp.cpp b/icespider/unittests/testApp.cpp
index 9b9155f..7df75f2 100644
--- a/icespider/unittests/testApp.cpp
+++ b/icespider/unittests/testApp.cpp
@@ -9,6 +9,7 @@
#include <Ice/ObjectAdapter.h>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
+#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem/operations.hpp>
#include <definedDirs.h>
#include <slicer/slicer.h>
@@ -211,6 +212,7 @@ BOOST_AUTO_TEST_CASE( testCallIndex )
process(&requestGetIndex);
auto h = parseHeaders(requestGetIndex.output);
BOOST_REQUIRE_EQUAL(h["Status"], "200 OK");
+ BOOST_REQUIRE_EQUAL(h["Content-Type"], "application/json");
auto v = Slicer::DeserializeAny<Slicer::JsonStreamDeserializer, TestIceSpider::SomeModelPtr>(requestGetIndex.output);
BOOST_REQUIRE_EQUAL(v->value, "index");
}
@@ -221,6 +223,7 @@ BOOST_AUTO_TEST_CASE( testCallViewSomething1234 )
process(&requestGetItem);
auto h = parseHeaders(requestGetItem.output);
BOOST_REQUIRE_EQUAL(h["Status"], "200 OK");
+ BOOST_REQUIRE_EQUAL(h["Content-Type"], "application/json");
auto v = Slicer::DeserializeAny<Slicer::JsonStreamDeserializer, TestIceSpider::SomeModelPtr>(requestGetItem.output);
BOOST_REQUIRE_EQUAL(v->value, "withParams");
}
@@ -231,6 +234,7 @@ BOOST_AUTO_TEST_CASE( testCallViewSomething1234_ )
process(&requestGetItemGiven);
auto h = parseHeaders(requestGetItemGiven.output);
BOOST_REQUIRE_EQUAL(h["Status"], "200 OK");
+ BOOST_REQUIRE_EQUAL(h["Content-Type"], "application/json");
auto v = Slicer::DeserializeAny<Slicer::JsonStreamDeserializer, TestIceSpider::SomeModelPtr>(requestGetItemGiven.output);
BOOST_REQUIRE_EQUAL(v->value, "withParams");
}
@@ -241,6 +245,7 @@ BOOST_AUTO_TEST_CASE( testCallViewSomething )
process(&requestGetItemDefault);
auto h = parseHeaders(requestGetItemDefault.output);
BOOST_REQUIRE_EQUAL(h["Status"], "200 OK");
+ BOOST_REQUIRE_EQUAL(h["Content-Type"], "application/json");
auto v = Slicer::DeserializeAny<Slicer::JsonStreamDeserializer, TestIceSpider::SomeModelPtr>(requestGetItemDefault.output);
BOOST_REQUIRE_EQUAL(v->value, "withParams");
}
@@ -274,6 +279,7 @@ BOOST_AUTO_TEST_CASE( testCallIndexAcceptJson )
process(&requestJson);
auto h = parseHeaders(requestJson.output);
BOOST_REQUIRE_EQUAL(h["Status"], "200 OK");
+ BOOST_REQUIRE_EQUAL(h["Content-Type"], "application/json");
auto v = Slicer::DeserializeAny<Slicer::JsonStreamDeserializer, TestIceSpider::SomeModelPtr>(requestJson.output);
BOOST_REQUIRE_EQUAL(v->value, "index");
}
@@ -296,6 +302,7 @@ BOOST_AUTO_TEST_CASE( testCallIndexAcceptApplicationAny )
process(&requestApplicationAny);
auto h = parseHeaders(requestApplicationAny.output);
BOOST_REQUIRE_EQUAL(h["Status"], "200 OK");
+ BOOST_REQUIRE(boost::algorithm::starts_with(h["Content-Type"], "application/"));
auto v = Slicer::DeserializeAny<Slicer::JsonStreamDeserializer, TestIceSpider::SomeModelPtr>(requestApplicationAny.output);
BOOST_REQUIRE_EQUAL(v->value, "index");
}
@@ -307,6 +314,7 @@ BOOST_AUTO_TEST_CASE( testCallIndexAcceptXml )
process(&requestXml);
auto h = parseHeaders(requestXml.output);
BOOST_REQUIRE_EQUAL(h["Status"], "200 OK");
+ BOOST_REQUIRE_EQUAL(h["Content-Type"], "application/xml");
auto v = Slicer::DeserializeAny<Slicer::XmlStreamDeserializer, TestIceSpider::SomeModelPtr>(requestXml.output);
BOOST_REQUIRE_EQUAL(v->value, "index");
}
@@ -318,6 +326,7 @@ BOOST_AUTO_TEST_CASE( testCallIndexAcceptTextHtml )
process(&requestHtml);
auto h = parseHeaders(requestHtml.output);
BOOST_REQUIRE_EQUAL(h["Status"], "200 OK");
+ BOOST_REQUIRE_EQUAL(h["Content-Type"], "text/html");
xmlpp::DomParser d;
d.parse_stream(requestHtml.output);
BOOST_REQUIRE_EQUAL(d.get_document()->get_root_node()->get_name(), "html");
@@ -352,6 +361,7 @@ BOOST_AUTO_TEST_CASE( testCallIndexComplexAccept )
process(&requestChoice);
auto h = parseHeaders(requestChoice.output);
BOOST_REQUIRE_EQUAL(h["Status"], "200 OK");
+ BOOST_REQUIRE_EQUAL(h["Content-Type"], "application/xml");
auto v = Slicer::DeserializeAny<Slicer::XmlStreamDeserializer, TestIceSpider::SomeModelPtr>(requestChoice.output);
BOOST_REQUIRE_EQUAL(v->value, "index");
}