diff options
-rw-r--r-- | project2/cgi/cgiContentNegotiate.cpp | 57 | ||||
-rw-r--r-- | project2/cgi/cgiEnvironment.cpp | 8 | ||||
-rw-r--r-- | project2/cgi/cgiEnvironment.h | 1 | ||||
-rw-r--r-- | project2/common/options.h | 11 | ||||
-rw-r--r-- | project2/xml/xmlPresenter.cpp | 2 |
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), |