summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrandomdan <randomdan@localhost>2013-03-23 16:45:24 +0000
committerrandomdan <randomdan@localhost>2013-03-23 16:45:24 +0000
commitc6fdb7e5defd272dbd6ec5d4627840d4094eb95c (patch)
treea9c508d6217d7c48ef539c66d4723d17e7553654
parentAllow script components to declare themselves uncacheable (diff)
downloadproject2-c6fdb7e5defd272dbd6ec5d4627840d4094eb95c.tar.bz2
project2-c6fdb7e5defd272dbd6ec5d4627840d4094eb95c.tar.xz
project2-c6fdb7e5defd272dbd6ec5d4627840d4094eb95c.zip
Adds a presenter loader that performs basic HTTP content negotiation
-rw-r--r--project2/cgi/cgiContentNegotiate.cpp57
-rw-r--r--project2/cgi/cgiEnvironment.cpp8
-rw-r--r--project2/cgi/cgiEnvironment.h1
-rw-r--r--project2/common/options.h11
-rw-r--r--project2/xml/xmlPresenter.cpp2
5 files changed, 76 insertions, 3 deletions
diff --git a/project2/cgi/cgiContentNegotiate.cpp b/project2/cgi/cgiContentNegotiate.cpp
new file mode 100644
index 0000000..8e265a8
--- /dev/null
+++ b/project2/cgi/cgiContentNegotiate.cpp
@@ -0,0 +1,57 @@
+#include <pch.hpp>
+#include "cgiAppEngine.h"
+#include <boost/tokenizer.hpp>
+
+class ContentNegotiateLoader : public PresenterLoader {
+ public:
+ ContentNegotiateLoader() :
+ opts("Content negotiation options")
+ {
+ opts
+ ("cgi.contentnegotiation.mappedtype", Options::value(&mappedTypes),
+ "mimetype=presenter list of types to negotiate")
+ ;
+ }
+
+ const Options * options() const { return &opts; }
+
+ MultiRowSetPresenter * create(const ScriptNodePtr & s, const ObjectSource & os) const
+ {
+ auto accept = static_cast<const CgiApplicationEngine *>(CgiApplicationEngine::getCurrent())->env()->getAccept();
+ typedef boost::tokenizer<boost::char_separator<char>> tokenizer;
+ BOOST_FOREACH(auto mimetypeAndWeight, tokenizer(accept, boost::char_separator<char>(","))) {
+ const auto mimetype = mimetypeAndWeight.substr(0, mimetypeAndWeight.find(';'));
+ if (mimetype == "*/*") break;
+ BOOST_FOREACH(const auto & t, mappedTypes) {
+ if (t.Matches(mimetype)) {
+ return PresenterLoader::getFor(t.present)->create(s, os);
+ }
+ }
+ }
+ return PresenterLoader::getFor(mappedTypes.begin()->present)->create(s, os);
+ }
+
+ Options opts;
+ class MappedType {
+ public:
+ MappedType(const std::string & val) :
+ accept(val.substr(0, val.find('='))),
+ present(val.substr(val.find('=') + 1))
+ {
+ }
+
+ bool Matches(const std::string & a) const
+ {
+ return (accept == a);
+ }
+
+ const std::string accept;
+ const std::string present;
+ };
+ std::vector<MappedType> mappedTypes;
+
+ bool cacheable() const { return false; }
+};
+
+DECLARE_CUSTOM_COMPONENT_LOADER("contentnegotiate", ContentNegotiateLoader, ContentNegotiateLoader, PresenterLoader);
+
diff --git a/project2/cgi/cgiEnvironment.cpp b/project2/cgi/cgiEnvironment.cpp
index 292a52f..c106f67 100644
--- a/project2/cgi/cgiEnvironment.cpp
+++ b/project2/cgi/cgiEnvironment.cpp
@@ -30,7 +30,7 @@ CgiEnvironment::CgiEnvironment() :
"The folder in which to find request scripts")
("cgi.errorPresentRoot", Options::value(&errorPresentRoot, "error"),
"The folder in which to find presentation scripts for error handling")
- ("cgi.errorContentType", Options::value(&errorContentType, "text/xml"),
+ ("cgi.errorContentType", Options::value(&errorContentType, "application/xml"),
"The Content-Type to use in HTTP headers in event of an error")
("cgi.errorTransformStyle", Options::value(&errorTransformStyle),
"The xml-stylesheet to specify in the data document in event of an error")
@@ -101,6 +101,12 @@ CgiEnvironment::getServerName() const
return cgi->getEnvironment().getServerName();
}
+std::string
+CgiEnvironment::getAccept() const
+{
+ return cgi->getEnvironment().getAccept();
+}
+
const Glib::ustring &
CgiEnvironment::platform() const
{
diff --git a/project2/cgi/cgiEnvironment.h b/project2/cgi/cgiEnvironment.h
index dd89a75..330cd97 100644
--- a/project2/cgi/cgiEnvironment.h
+++ b/project2/cgi/cgiEnvironment.h
@@ -42,6 +42,7 @@ class CgiEnvironment : public Environment {
std::string getScriptName() const;
std::string getRedirectURL() const;
std::string getRequestMethod() const;
+ std::string getAccept() const;
ETags getRequestETags() const;
time_t getRequestModifiedSince() const;
std::string getCookieValue(const std::string & name) const;
diff --git a/project2/common/options.h b/project2/common/options.h
index a28b5f8..93c6aa5 100644
--- a/project2/common/options.h
+++ b/project2/common/options.h
@@ -99,10 +99,19 @@ class Options {
target->clear();
}
void assign(const Glib::ustring & value) const {
- target->push_back(boost::lexical_cast<T>(value));
+ doAssign(value);
}
protected:
VofT * target;
+ private:
+ template <typename dummy = int>
+ void doAssign(const Glib::ustring & value, typename boost::disable_if<std::is_constructible<T, Glib::ustring>, dummy>::type = 0) const {
+ target->push_back(boost::lexical_cast<T>(value));
+ }
+ template <typename dummy = int>
+ void doAssign(const Glib::ustring & value, typename boost::enable_if<std::is_constructible<T, Glib::ustring>, dummy>::type = 0) const {
+ target->push_back(T(value));
+ }
};
class Option : public IntrusivePtrBase {
diff --git a/project2/xml/xmlPresenter.cpp b/project2/xml/xmlPresenter.cpp
index 45836a2..ddb1e03 100644
--- a/project2/xml/xmlPresenter.cpp
+++ b/project2/xml/xmlPresenter.cpp
@@ -77,7 +77,7 @@ XmlPresenter::XmlPresenter(const Glib::ustring & responseRootNodeName, const Gli
XmlPresenter::XmlPresenter(ScriptNodePtr e, ObjectSource os) :
TransformSource(e, os),
Presenter(os),
- ContentPresenter(e->value("contenttype", "text/xml")),
+ ContentPresenter(e->value("contenttype", "application/xml")),
SourceOf<xmlpp::Document>(e, os),
SourceOf<_xmlDoc>(e, os),
SourceOf<boost::shared_ptr<xmlpp::Document> >(e, os),