diff options
| -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 | 
