diff options
author | Dan Goodliffe <dan@randomdan.homeip.net> | 2016-06-22 22:49:23 +0100 |
---|---|---|
committer | Dan Goodliffe <dan@randomdan.homeip.net> | 2016-06-22 22:49:23 +0100 |
commit | ec5aef094cbcb9769c50a7e7a6a344036e01f67b (patch) | |
tree | 78e6986b60b076c781c1876eb5455226e9582f4f | |
parent | Determine return type based on second arg to all chaining (diff) | |
download | icespider-ec5aef094cbcb9769c50a7e7a6a344036e01f67b.tar.bz2 icespider-ec5aef094cbcb9769c50a7e7a6a344036e01f67b.tar.xz icespider-ec5aef094cbcb9769c50a7e7a6a344036e01f67b.zip |
Very basic, probably buggy, incomplete [f]cgi implementation
-rw-r--r-- | icespider/core/Jamfile.jam | 2 | ||||
-rw-r--r-- | icespider/core/util.h | 8 | ||||
-rw-r--r-- | icespider/fcgi/Jamfile.jam | 3 | ||||
-rw-r--r-- | icespider/fcgi/cgiRequest.cpp | 25 | ||||
-rw-r--r-- | icespider/fcgi/cgiRequest.h | 17 | ||||
-rw-r--r-- | icespider/fcgi/cgiRequestBase.cpp | 99 | ||||
-rw-r--r-- | icespider/fcgi/cgiRequestBase.h | 38 | ||||
-rw-r--r-- | icespider/fcgi/fcgiRequest.cpp | 26 | ||||
-rw-r--r-- | icespider/fcgi/fcgiRequest.h | 23 | ||||
-rw-r--r-- | icespider/fcgi/main.cpp | 18 | ||||
-rw-r--r-- | icespider/unittests/Jamfile.jam | 10 | ||||
-rw-r--r-- | icespider/unittests/testFcgi.cpp | 1 |
12 files changed, 265 insertions, 5 deletions
diff --git a/icespider/core/Jamfile.jam b/icespider/core/Jamfile.jam index 6a99e84..5dbaf31 100644 --- a/icespider/core/Jamfile.jam +++ b/icespider/core/Jamfile.jam @@ -12,4 +12,6 @@ lib icespider-core : <implicit-dependency>../common : : <include>. + <library>../common + <implicit-dependency>../common ; diff --git a/icespider/core/util.h b/icespider/core/util.h index 075f237..03a01a9 100644 --- a/icespider/core/util.h +++ b/icespider/core/util.h @@ -12,5 +12,13 @@ namespace IceUtil { } } +template <typename T> +T orelse(const T & a, const T & b) +{ + if (a) return a; + return b; +} + + #endif diff --git a/icespider/fcgi/Jamfile.jam b/icespider/fcgi/Jamfile.jam index eb0c3f2..c607ed1 100644 --- a/icespider/fcgi/Jamfile.jam +++ b/icespider/fcgi/Jamfile.jam @@ -1,7 +1,10 @@ lib fcgi : : <name>fcgi ; +lib fcgi++ : : <name>fcgi++ ; lib icespider-fcgi : [ glob-tree *.cpp : bin ] : <library>fcgi + <library>fcgi++ + <library>..//core ; diff --git a/icespider/fcgi/cgiRequest.cpp b/icespider/fcgi/cgiRequest.cpp new file mode 100644 index 0000000..abc3bea --- /dev/null +++ b/icespider/fcgi/cgiRequest.cpp @@ -0,0 +1,25 @@ +#include "cgiRequest.h" + +namespace IceSpider { + CgiRequest::CgiRequest(IceSpider::Core * c, int argc, char ** argv, char ** env) : + CgiRequestBase(c, env) + { + for (; argc > 0;) { + addenv(argv[--argc]); + } + initialize(); + } + + std::istream & + CgiRequest::getInputStream() const + { + return std::cin; + } + + std::ostream & + CgiRequest::getOutputStream() const + { + return std::cout; + } +} + diff --git a/icespider/fcgi/cgiRequest.h b/icespider/fcgi/cgiRequest.h new file mode 100644 index 0000000..9af58bb --- /dev/null +++ b/icespider/fcgi/cgiRequest.h @@ -0,0 +1,17 @@ +#ifndef ICESPIDER_CGI_CGIREQUEST_H +#define ICESPIDER_CGI_CGIREQUEST_H + +#include "cgiRequestBase.h" + +namespace IceSpider { + class CgiRequest : public CgiRequestBase { + public: + CgiRequest(IceSpider::Core * c, int argc, char ** argv, char ** env); + + std::istream & getInputStream() const override; + std::ostream & getOutputStream() const override; + }; +} + +#endif + diff --git a/icespider/fcgi/cgiRequestBase.cpp b/icespider/fcgi/cgiRequestBase.cpp new file mode 100644 index 0000000..97a71fc --- /dev/null +++ b/icespider/fcgi/cgiRequestBase.cpp @@ -0,0 +1,99 @@ +#include "cgiRequestBase.h" +#include <boost/algorithm/string/case_conv.hpp> +#include <boost/algorithm/string/split.hpp> +#include <util.h> + +namespace ba = boost::algorithm; + +namespace IceSpider { + CgiRequestBase::CgiRequestBase(IceSpider::Core * c, char ** env) : + IceSpider::IHttpRequest(c) + { + for(char * const * e = env; *e; ++e) { + addenv(*e); + } + } + + void + CgiRequestBase::addenv(char * e) + { + if (auto eq = strchr(e, '=')) { + *eq++ = '\0'; + envmap.insert({ e, Env(eq, strchr(eq, '\0')) }); + } + } + + void + CgiRequestBase::initialize() + { + auto qs = envmap.find("QUERY_STRING"); + if (qs != envmap.end()) { + auto start = std::get<0>(qs->second); + auto end = std::get<1>(qs->second); + while (start < end) { + auto amp = orelse(strchr(start, '&'), end); + auto eq = orelse(strchr(start, '='), end); + if (eq < amp) { + *eq = '\0'; + *amp = '\0'; + qsmap.insert({ eq, Env( eq + 1, amp ) }); + } + else { + *eq = '\0'; + *amp = '\0'; + qsmap.insert({ eq, Env( eq + 1, eq + 1 ) }); + } + start = amp + 1; + } + } + } + + IceUtil::Optional<std::string> + CgiRequestBase::optionalLookup(const std::string & key, const VarMap & vm) + { + auto i = vm.find(key.c_str()); + if (i == vm.end()) { + return IceUtil::Optional<std::string>(); + } + return std::string(std::get<0>(i->second), std::get<1>(i->second)); + } + + std::string + CgiRequestBase::getRequestPath() const + { + return optionalLookup("REDIRECT_URL", envmap) / + [this]() { return optionalLookup("SCRIPT_NAME", envmap); } / + [this]() -> std::string { throw std::runtime_error("Couldn't determine request path"); }; + } + + UserIceSpider::HttpMethod + CgiRequestBase::getRequestMethod() const + { + return UserIceSpider::HttpMethod::GET; + } + + IceUtil::Optional<std::string> + CgiRequestBase::getURLParam(const std::string & key) const + { + return optionalLookup(key, pathmap); + } + + IceUtil::Optional<std::string> + CgiRequestBase::getQueryStringParam(const std::string & key) const + { + return optionalLookup(key, qsmap); + } + + IceUtil::Optional<std::string> + CgiRequestBase::getHeaderParam(const std::string & key) const + { + return optionalLookup(("HTTP_" + boost::algorithm::to_upper_copy(key)).c_str(), envmap); + } + + bool + CgiRequestBase::cmp_str::operator()(char const * a, char const * b) const + { + return std::strcmp(a, b) < 0; + } +} + diff --git a/icespider/fcgi/cgiRequestBase.h b/icespider/fcgi/cgiRequestBase.h new file mode 100644 index 0000000..8a6d207 --- /dev/null +++ b/icespider/fcgi/cgiRequestBase.h @@ -0,0 +1,38 @@ +#ifndef ICESPIDER_CGI_CGIREQUESTBASE_H +#define ICESPIDER_CGI_CGIREQUESTBASE_H + +#include <core.h> +#include <ihttpRequest.h> +#include <map> +#include <tuple> + +namespace IceSpider { + class CgiRequestBase : public IceSpider::IHttpRequest { + protected: + struct cmp_str { + bool operator()(char const *a, char const *b) const; + }; + + typedef std::tuple<char *, char *> Env; + typedef std::map<const char *, Env, cmp_str> VarMap; + + CgiRequestBase(IceSpider::Core * c, char ** env); + void addenv(char *); + void initialize(); + + std::string getRequestPath() const override; + UserIceSpider::HttpMethod getRequestMethod() const override; + IceUtil::Optional<std::string> getURLParam(const std::string & key) const override; + IceUtil::Optional<std::string> getQueryStringParam(const std::string & key) const override; + IceUtil::Optional<std::string> getHeaderParam(const std::string & key) const override; + + static IceUtil::Optional<std::string> optionalLookup(const std::string & key, const VarMap &); + + VarMap envmap; + VarMap qsmap; + VarMap pathmap; + }; +} + +#endif + diff --git a/icespider/fcgi/fcgiRequest.cpp b/icespider/fcgi/fcgiRequest.cpp new file mode 100644 index 0000000..484f12f --- /dev/null +++ b/icespider/fcgi/fcgiRequest.cpp @@ -0,0 +1,26 @@ +#include "fcgiRequest.h" + +namespace IceSpider { + FcgiRequest::FcgiRequest(IceSpider::Core * c, FCGX_Request * r) : + CgiRequestBase(c, r->envp), + inputbuf(r->in), + input(&inputbuf), + outputbuf(r->out), + output(&outputbuf) + { + initialize(); + } + + std::istream & + FcgiRequest::getInputStream() const + { + return input; + } + + std::ostream & + FcgiRequest::getOutputStream() const + { + return output; + } +} + diff --git a/icespider/fcgi/fcgiRequest.h b/icespider/fcgi/fcgiRequest.h new file mode 100644 index 0000000..ec5b65b --- /dev/null +++ b/icespider/fcgi/fcgiRequest.h @@ -0,0 +1,23 @@ +#ifndef ICESPIDER_CGI_FCGIREQUEST_H +#define ICESPIDER_CGI_FCGIREQUEST_H + +#include "cgiRequestBase.h" +#include <fcgio.h> + +namespace IceSpider { + class FcgiRequest : public CgiRequestBase { + public: + FcgiRequest(IceSpider::Core * c, FCGX_Request * r); + + std::istream & getInputStream() const override; + std::ostream & getOutputStream() const override; + + fcgi_streambuf inputbuf; + mutable std::istream input; + fcgi_streambuf outputbuf; + mutable std::ostream output; + }; +} + +#endif + diff --git a/icespider/fcgi/main.cpp b/icespider/fcgi/main.cpp index 6132769..1d2e68c 100644 --- a/icespider/fcgi/main.cpp +++ b/icespider/fcgi/main.cpp @@ -1,8 +1,14 @@ -#include <fcgio.h> +#include <visibility.h> +#include "fcgiRequest.h" +#include "cgiRequest.h" +using namespace IceSpider; + +DLL_PUBLIC int -main(void) +main(int argc, char ** argv, char ** env) { + IceSpider::Core core; if (!FCGX_IsCGI()) { FCGX_Request request; @@ -10,13 +16,15 @@ main(void) FCGX_InitRequest(&request, 0, 0); while (FCGX_Accept_r(&request) == 0) { - // app.process(IO, &IO, IO); + FcgiRequest r(&core, &request); + core.process(&r); FCGX_Finish_r(&request); } - return 0; } else { - return 1; + CgiRequest r(&core, argc, argv, env); + core.process(&r); } + return 0; } diff --git a/icespider/unittests/Jamfile.jam b/icespider/unittests/Jamfile.jam index b9a861b..d948b29 100644 --- a/icespider/unittests/Jamfile.jam +++ b/icespider/unittests/Jamfile.jam @@ -69,6 +69,16 @@ run <dependency>../compile : testApp ; +run + testFcgi.cpp + : + 'QUERY_STRING=noeq&noval=&someval=here&another=here' + 'REDIRECT_URL=/' + : : + <library>../common//icespider-common + <library>../core//icespider-core + <library>../fcgi//icespider-fcgi + : testFcgi ; lib test-api : test-api.ice diff --git a/icespider/unittests/testFcgi.cpp b/icespider/unittests/testFcgi.cpp new file mode 100644 index 0000000..65e2cc3 --- /dev/null +++ b/icespider/unittests/testFcgi.cpp @@ -0,0 +1 @@ +// intentionally blank |