diff options
| -rw-r--r-- | icespider/fcgi/cgiRequestBase.cpp | 31 | ||||
| -rw-r--r-- | icespider/fcgi/cgiRequestBase.h | 3 | ||||
| -rw-r--r-- | icespider/fcgi/xwwwFormUrlEncoded.cpp | 222 | ||||
| -rw-r--r-- | icespider/fcgi/xwwwFormUrlEncoded.h | 34 | ||||
| -rw-r--r-- | icespider/unittests/testFcgi.cpp | 9 | 
5 files changed, 183 insertions, 116 deletions
| diff --git a/icespider/fcgi/cgiRequestBase.cpp b/icespider/fcgi/cgiRequestBase.cpp index c36e11c..efa9468 100644 --- a/icespider/fcgi/cgiRequestBase.cpp +++ b/icespider/fcgi/cgiRequestBase.cpp @@ -1,4 +1,5 @@  #include "cgiRequestBase.h" +#include "xwwwFormUrlEncoded.h"  #include <boost/algorithm/string/case_conv.hpp>  #include <boost/algorithm/string/split.hpp>  #include <boost/algorithm/string/classification.hpp> @@ -40,21 +41,9 @@ namespace IceSpider {  		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); -				*amp = '\0'; -				if (eq < amp) { -					*eq = '\0'; -					qsmap.insert({ start, Env( eq + 1, amp ) }); -				} -				else { -					qsmap.insert({ start, Env( eq + 1, eq + 1 ) }); -				} -				start = amp + 1; -			} +			XWwwFormUrlEncoded::iterateVars(std::string(std::get<0>(qs->second), std::get<1>(qs->second)), [this](auto k, auto v) { +				qsmap.insert({ k, v }); +			});  		}  	} @@ -63,11 +52,21 @@ namespace IceSpider {  	{  		auto i = vm.find(key.c_str());  		if (i == vm.end()) { -			return IceUtil::Optional<std::string>(); +			return IceUtil::None;  		}  		return std::string(std::get<0>(i->second), std::get<1>(i->second));  	} +	OptionalString +	CgiRequestBase::optionalLookup(const std::string & key, const StringMap & vm) +	{ +		auto i = vm.find(key.c_str()); +		if (i == vm.end()) { +			return IceUtil::None; +		} +		return i->second; +	} +  	const PathElements &  	CgiRequestBase::getRequestPath() const  	{ diff --git a/icespider/fcgi/cgiRequestBase.h b/icespider/fcgi/cgiRequestBase.h index 97d956a..20d7d05 100644 --- a/icespider/fcgi/cgiRequestBase.h +++ b/icespider/fcgi/cgiRequestBase.h @@ -29,9 +29,10 @@ namespace IceSpider {  		private:  			static OptionalString optionalLookup(const std::string & key, const VarMap &); +			static OptionalString optionalLookup(const std::string & key, const StringMap &);  			VarMap envmap; -			VarMap qsmap; +			StringMap qsmap;  			PathElements pathElements;  	};  } diff --git a/icespider/fcgi/xwwwFormUrlEncoded.cpp b/icespider/fcgi/xwwwFormUrlEncoded.cpp index a2ca9ee..2f60367 100644 --- a/icespider/fcgi/xwwwFormUrlEncoded.cpp +++ b/icespider/fcgi/xwwwFormUrlEncoded.cpp @@ -1,6 +1,5 @@ -#include <slicer/slicer.h> +#include "xwwwFormUrlEncoded.h"  #include <exceptions.h> -#include <boost/algorithm/string/split.hpp>  #include <boost/lexical_cast.hpp>  #include <Ice/BuiltinSequences.h> @@ -10,116 +9,141 @@ extern long hextable[];  namespace IceSpider { -	class XWwwFormUrlEncoded : public Slicer::Deserializer { +	XWwwFormUrlEncoded::XWwwFormUrlEncoded(std::istream & in) : +		input(std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>()) +	{ +	} + +	void +	XWwwFormUrlEncoded::Deserialize(Slicer::ModelPartForRootPtr mp) +	{ +		mp->Create(); +		mp->OnEachChild([this](auto, auto mp, auto) { +			switch (mp->GetType()) { +				case Slicer::mpt_Simple: +					this->DeserializeSimple(mp); +					break; +				case Slicer::mpt_Complex: +					this->DeserializeComplex(mp); +					break; +				case Slicer::mpt_Dictionary: +					this->DeserializeDictionary(mp); +					break; +				default: +					throw IceSpider::Http400_BadRequest(); +					break; +			} +		}); +		mp->Complete(); +	} + +	class SetFromString : public Slicer::ValueSource {  		public: -			XWwwFormUrlEncoded(std::istream & in) : -				input(std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>()) +			SetFromString(const std::string & v) : s(v)  			{  			} -			void Deserialize(Slicer::ModelPartForRootPtr mp) override +			void set(bool & t) const override  			{ -				mp->Create(); -				mp->OnEachChild([this](auto, auto mp, auto) { -					switch (mp->GetType()) { -						case Slicer::mpt_Simple: -							this->DeserializeSimple(mp); -							break; -						case Slicer::mpt_Complex: -							this->DeserializeComplex(mp); -							break; -						case Slicer::mpt_Dictionary: -							this->DeserializeDictionary(mp); -							break; -						default: -							throw IceSpider::Http400_BadRequest(); -							break; -					} -				}); -				mp->Complete(); +				if (s == "true") t = true; +				else if (s == "false") t = false; +				else throw Http400_BadRequest();  			} -		private: -			class SetFromString : public Slicer::ValueSource { -				public: -					SetFromString(const std::string & v) : s(v) -					{ -					} - -					void set(bool & t) const override -					{ -						if (s == "true") t = true; -						else if (s == "false") t = false; -						else throw Http400_BadRequest(); -					} - -					void set(std::string & t) const override -					{ -						t.reserve(s.size()); -						for (auto i = s.begin(); i != s.end(); i++) { -							if (*i == '+') t += ' '; -							else if (*i == '%') { -								t += (16 * hextable[(int)*++i]) + hextable[(int)*++i]; -							} -							else t += *i; -						} -					} +			void set(std::string & t) const override +			{ +				t = s; +			}  #define SET(T) \ -					void set(T & t) const override \ -					{ \ -						t = boost::lexical_cast<T>(s); \ -					} - -					SET(Ice::Byte); -					SET(Ice::Short); -					SET(Ice::Int); -					SET(Ice::Long); -					SET(Ice::Float); -					SET(Ice::Double); -					const std::string & s; -			}; - -			typedef boost::function<void(const std::string &, const std::string &)> KVh; -			void iterateVars(const KVh & h) -			{ -				for (auto pi = ba::make_split_iterator(input, ba::first_finder("&", ba::is_equal())); pi != decltype(pi)(); ++pi) { -					auto eq = std::find(pi->begin(), pi->end(), '='); -					if (eq == pi->end()) { -						h(std::string(pi->begin(), pi->end()), std::string()); -					} -					else { -						h(std::string(pi->begin(), eq), std::string(eq + 1, pi->end())); -					} -				} +			void set(T & t) const override \ +			{ \ +				t = boost::lexical_cast<T>(s); \  			} -			void DeserializeSimple(Slicer::ModelPartPtr mp) -			{ -				iterateVars([mp](auto, auto v) { -					mp->SetValue(new SetFromString(v)); -				}); + +			SET(Ice::Byte); +			SET(Ice::Short); +			SET(Ice::Int); +			SET(Ice::Long); +			SET(Ice::Float); +			SET(Ice::Double); +			const std::string & s; +	}; + +	std::string +	XWwwFormUrlEncoded::urldecode(std::string::const_iterator i, std::string::const_iterator e) +	{ +		std::string t; +		t.reserve(&*e - &*i); +		while (i != e) { +			if (*i == '+') t += ' '; +			else if (*i == '%') { +				t += (16 * hextable[(int)*++i]) + hextable[(int)*++i];  			} -			void DeserializeComplex(Slicer::ModelPartPtr mp) -			{ -				mp->Create(); -				iterateVars([mp](auto k, auto v) { -					if (auto m = mp->GetChild(k)) { -						m->SetValue(new SetFromString(v)); -					} -				}); -				mp->Complete(); +			else t += *i; +			++i; +		} +		return t; +	} + +	void +	XWwwFormUrlEncoded::iterateVars(const KVh & h, ba::split_iterator<std::string::const_iterator> pi) +	{ +		for (; pi != decltype(pi)(); ++pi) { +			auto eq = std::find(pi->begin(), pi->end(), '='); +			if (eq == pi->end()) { +				h(urldecode(pi->begin(), pi->end()), std::string());  			} -			void DeserializeDictionary(Slicer::ModelPartPtr mp) -			{ -				iterateVars([mp](auto k, auto v) { -					auto p = mp->GetAnonChild(); -					p->GetChild("key")->SetValue(new SetFromString(k)); -					p->GetChild("value")->SetValue(new SetFromString(v)); -					p->Complete(); -				}); +			else { +				h(urldecode(pi->begin(), eq), urldecode(eq + 1, pi->end()));  			} -			const std::string input; -	}; +		} +	} + +	void +	XWwwFormUrlEncoded::iterateVars(const std::string & input, const KVh & h) +	{ +		if (!input.empty()) { +			iterateVars(h, ba::make_split_iterator(input, ba::first_finder("&", ba::is_equal()))); +		} +	} + +	void +	XWwwFormUrlEncoded::iterateVars(const KVh & h) +	{ +		iterateVars(input, h); +	} + +	void +	XWwwFormUrlEncoded::DeserializeSimple(Slicer::ModelPartPtr mp) +	{ +		iterateVars([mp](auto, auto v) { +			mp->SetValue(new SetFromString(v)); +		}); +	} + +	void +	XWwwFormUrlEncoded::DeserializeComplex(Slicer::ModelPartPtr mp) +	{ +		mp->Create(); +		iterateVars([mp](auto k, auto v) { +			if (auto m = mp->GetChild(k)) { +				m->SetValue(new SetFromString(v)); +			} +		}); +		mp->Complete(); +	} + +	void +	XWwwFormUrlEncoded::DeserializeDictionary(Slicer::ModelPartPtr mp) +	{ +		iterateVars([mp](auto k, auto v) { +			auto p = mp->GetAnonChild(); +			p->GetChild("key")->SetValue(new SetFromString(k)); +			p->GetChild("value")->SetValue(new SetFromString(v)); +			p->Complete(); +		}); +	}  }  NAMEDFACTORY("application/x-www-form-urlencoded", IceSpider::XWwwFormUrlEncoded, Slicer::StreamDeserializerFactory); diff --git a/icespider/fcgi/xwwwFormUrlEncoded.h b/icespider/fcgi/xwwwFormUrlEncoded.h new file mode 100644 index 0000000..fe6aa00 --- /dev/null +++ b/icespider/fcgi/xwwwFormUrlEncoded.h @@ -0,0 +1,34 @@ +#ifndef ICESPIDER_CGI_XWWWFORMURLENCODED_H +#define ICESPIDER_CGI_XWWWFORMURLENCODED_H + +#include <slicer/serializer.h> +#include <boost/algorithm/string/split.hpp> + +namespace IceSpider { +	class XWwwFormUrlEncoded : public Slicer::Deserializer { +		public: +			typedef boost::function<void(const std::string &, const std::string &)> KVh; + +			XWwwFormUrlEncoded(std::istream & in); + +			void Deserialize(Slicer::ModelPartForRootPtr mp) override; +			static inline void iterateVars(const std::string & input, const KVh & h); + +		private: + +			static inline void iterateVars(const KVh & h, boost::algorithm::split_iterator<std::string::const_iterator> pi); +			static std::string urldecode(std::string::const_iterator s, std::string::const_iterator); + +			void iterateVars(const KVh & h); + +			void DeserializeSimple(Slicer::ModelPartPtr mp); +			void DeserializeComplex(Slicer::ModelPartPtr mp); +			void DeserializeDictionary(Slicer::ModelPartPtr mp); + +			const std::string input; +	}; + +}; + +#endif + diff --git a/icespider/unittests/testFcgi.cpp b/icespider/unittests/testFcgi.cpp index 94ce092..923c28d 100644 --- a/icespider/unittests/testFcgi.cpp +++ b/icespider/unittests/testFcgi.cpp @@ -151,6 +151,15 @@ BOOST_AUTO_TEST_CASE( query_string_three )  	BOOST_REQUIRE_EQUAL("3", *r.getQueryStringParam("three"));  } +BOOST_AUTO_TEST_CASE( query_string_urlencoding ) +{ +	CharPtrPtrArray env ({ "SCRIPT_NAME=/foo/bar", "QUERY_STRING=url+%65ncoded=%53tring%2e" }); +	TestRequest r(this, env); +	BOOST_REQUIRE(!r.getQueryStringParam("")); +	BOOST_REQUIRE(r.getQueryStringParam("url encoded")); +	BOOST_REQUIRE_EQUAL("String.", *r.getQueryStringParam("url encoded")); +} +  BOOST_AUTO_TEST_CASE( query_string_three_emptyVal )  {  	CharPtrPtrArray env ({ "SCRIPT_NAME=/foo/bar", "QUERY_STRING=one=1&two=&three=3" }); | 
