diff options
| -rw-r--r-- | project2/cgi/cgiAppEngine.cpp | 6 | ||||
| -rw-r--r-- | project2/cgi/cgiEnvironment.cpp | 29 | ||||
| -rw-r--r-- | project2/cgi/cgiEnvironment.h | 8 | ||||
| -rw-r--r-- | project2/cgi/cgiProgRouter.cpp | 186 | ||||
| -rw-r--r-- | project2/cgi/cgiRouter.h | 20 | ||||
| -rw-r--r-- | project2/cgi/cgiSimpleRouter.cpp | 55 | ||||
| -rw-r--r-- | project2/cgi/cgiStageInitial.cpp | 9 | ||||
| -rw-r--r-- | project2/common/environment.h | 2 | ||||
| -rw-r--r-- | project2/common/options.h | 34 | ||||
| -rw-r--r-- | project2/common/typePointer.h | 17 | ||||
| -rw-r--r-- | project2/common/variables-moduri.cpp | 6 | ||||
| -rw-r--r-- | project2/console/consoleEnvironment.cpp | 5 | ||||
| -rw-r--r-- | project2/console/consoleEnvironment.h | 2 | ||||
| -rw-r--r-- | project2/xml/xmlPresenter.cpp | 2 | 
14 files changed, 300 insertions, 81 deletions
diff --git a/project2/cgi/cgiAppEngine.cpp b/project2/cgi/cgiAppEngine.cpp index 28600b3..f2c7f86 100644 --- a/project2/cgi/cgiAppEngine.cpp +++ b/project2/cgi/cgiAppEngine.cpp @@ -178,11 +178,7 @@ CgiApplicationEngine::addEnvData(const MultiRowSetPresenter * p, OutputOptionsPt  		// URL elements  		p->addNewRowSet("uriElems", env()->scriptNamespacePrefix);  		p->addAttribute("full", _env->getRedirectURL()); -		p->addNewArray("uriElem", true); -		BOOST_FOREACH(std::string s, _env->elems) { -			p->addNamedValue("uriElem", s); -		} -		p->finishArray(true); +		_env->router->present(p);  		p->finishRowSet();  	} diff --git a/project2/cgi/cgiEnvironment.cpp b/project2/cgi/cgiEnvironment.cpp index 439f6d8..292a52f 100644 --- a/project2/cgi/cgiEnvironment.cpp +++ b/project2/cgi/cgiEnvironment.cpp @@ -9,22 +9,6 @@  #include <glibmm/regex.h>  #include <curl/curl.h> -std::vector<std::string> -makeVector(const boost::filesystem::path & y) -{ -	std::vector<std::string> r; -	boost::filesystem::path::iterator p = y.begin(); -	p++; -	while(p != y.end()) { -#if BOOST_VERSION >= 104500 -		r.push_back((p++)->string()); -#else -		r.push_back(*(p++)); -#endif -	} -	return r; -} -  CgiEnvironment::CgiEnvironment() :  	cgi(NULL),  	cgienv(NULL), @@ -60,6 +44,8 @@ CgiEnvironment::CgiEnvironment() :  		 "The module with which to implement session management")  		("cgi.hostRegex", hpi,  		 "Regular expression used to define a hostname -> platform association") +		("cgi.router", Options::value(&routerType, "simple"), +		 "Implemenation of router model to map request paths to scripts")  		;  } @@ -77,7 +63,7 @@ CgiEnvironment::setCGICC(const cgicc::Cgicc * c, const CgiEnvInput * e)  {  	cgi = c;  	cgienv = e; -	elems = makeVector(boost::filesystem::path(getRedirectURL())); +	router = boost::bind(&GenLoader<Router, const std::string &>::createNew, boost::cref(routerType), getRedirectURL());  }  std::string @@ -137,18 +123,15 @@ CgiEnvironment::getRequestModifiedSince() const  }  Glib::ustring -CgiEnvironment::getParamUri(unsigned int p) const +CgiEnvironment::getParamUri(VariableType p) const  { -	if (p >= elems.size()) { -		throw UriElementOutOfRange(p); -	} -	return elems[p]; +	return router->routeParameter(p);  }  unsigned int  CgiEnvironment::getParamUriCount() const  { -	return elems.size(); +	return router->parameterCount();  }  Glib::ustring diff --git a/project2/cgi/cgiEnvironment.h b/project2/cgi/cgiEnvironment.h index 6797a24..dd89a75 100644 --- a/project2/cgi/cgiEnvironment.h +++ b/project2/cgi/cgiEnvironment.h @@ -5,7 +5,9 @@  #include <vector>  #include "environment.h"  #include "cgiEnvInput.h" +#include "cgiRouter.h"  #include <cgicc/CgiEnvironment.h> +#include <lazyPointer.h>  SimpleMessageException(NoSuchCookie); @@ -33,7 +35,7 @@ class CgiEnvironment : public Environment {  		CgiEnvironment();  		virtual ~CgiEnvironment(); -		Glib::ustring getParamUri(unsigned int idx) const; +		Glib::ustring getParamUri(VariableType idx) const;  		unsigned int getParamUriCount() const;  		Glib::ustring getParamQuery(const std::string & idx) const;  		std::string getServerName() const; @@ -47,7 +49,6 @@ class CgiEnvironment : public Environment {  		void setCGICC(const cgicc::Cgicc *, const CgiEnvInput * cgienv);  		const cgicc::Cgicc * cgi;  		const CgiEnvInput * cgienv; -		std::vector<std::string> elems;  	private:  		const Options & engineOptions() const; @@ -69,6 +70,9 @@ class CgiEnvironment : public Environment {  		std::string onErrorPresent;  		std::string defaultPresenter;  		std::string sessionModule; +		std::string routerType; +		typedef LazyPointer<const Router> RouterPtr; +		RouterPtr router;  };  #endif diff --git a/project2/cgi/cgiProgRouter.cpp b/project2/cgi/cgiProgRouter.cpp new file mode 100644 index 0000000..9218c89 --- /dev/null +++ b/project2/cgi/cgiProgRouter.cpp @@ -0,0 +1,186 @@ +#include <pch.hpp> +#include <boost/algorithm/string/predicate.hpp> +#include "cgiEnvironment.h" +#include "safeMapFind.h" +#include "exceptions.h" + +typedef std::map<std::string, std::string> VarMap; + +class RoutingTable { +	public: +		RoutingTable & operator=(const std::string & routeFile) { +			routes.clear(); +			routeScriptPath = routeFile; +			if (routeFile.empty()) { +				routeScript.reset(); +			} +			else { +				setRouteScript(); +			} +			return *this; +		} + +		void onBefore() +		{ +			if (routeScript && !routeScript->isCurrent()) { +				setRouteScript(); +			} +		} +		void setRouteScript() +		{ +			routeScript = Environment::getCurrent()->resolveScript(Environment::getCurrent()->datasourceRoot, routeScriptPath, true); +			routeScript->loader.addLoadTarget(routeScript->root(), Storer::into<ElementLoader>(&routes)); +			routeScript->load(NULL, true); +		} +		ScriptReaderPtr routeScript; +		std::string routeScriptPath; + +		const std::string & present(const std::string & path, VarMap & vars) const { +			BOOST_FOREACH(const auto route, routes) { +				vars.clear(); +				if (route->matches(path, vars)) { +					return route->present; +				} +			} +			throw ScriptNotFound("routed", path); +		} + +		class RouteElem : public IntrusivePtrBase { +			public: +				virtual bool matches(const std::string &, VarMap & vars) const = 0; +		}; +		typedef boost::intrusive_ptr<RouteElem> RouteElemPtr; + +		class RouteLiteral : public RouteElem { +			public: +				RouteLiteral(const std::string & v) : value(v) { } +				bool matches(const std::string & path, VarMap &) const { +					return value == path; +				} +				const std::string value; +		}; + +		class RouteVar : public RouteElem { +			public: +				RouteVar(const std::string & v) : variable(v.substr(1, v.length() - 2)) { } +				bool matches(const std::string & value, VarMap & vars) const { +					vars[variable] = value; +					return true; +				} +				const std::string variable; +		}; +		 +		class Route : public SourceObject { +			public: +				Route(ScriptNodePtr s) : +					SourceObject(s), +					present(s->value("present").as<std::string>()) +				{ +					boost::filesystem::path path = s->value("path").as<std::string>(); +					boost::filesystem::path::iterator p = path.begin(); +					p++; +					while(p != path.end() && p->string() != ".") { +						switch (p->string().front()) { +							case '{': +								routeElems.push_back(new RouteVar(p->string())); +								break; +							default: +								routeElems.push_back(new RouteLiteral(p->string())); +								break; +						} +						p++; +					} +				} +				bool matches(const boost::filesystem::path & path, VarMap & vars) const { +					boost::filesystem::path::iterator p = path.begin(); +					p++; +					for (RouteElems::const_iterator re = routeElems.begin(); re != routeElems.end() || p != path.end(); re++) { +						if (re == routeElems.end() || p == path.end() || !(*re)->matches(p->string(), vars)) { +							return false; +						} +						while (++p != path.end() && p->string() == ".") ; +					} +					return true; +				} +				typedef std::list<RouteElemPtr> RouteElems; +				RouteElems routeElems; +				const std::string present; +		}; +		typedef boost::intrusive_ptr<Route> RoutePtr; + +		std::list<RoutePtr> routes; +}; + +typedef RoutingTable::Route Route; +DECLARE_LOADER("route", Route); + +class ProgRouter; +class ProgRouterLoader : public RouterLoader::For<ProgRouter> { +	public: +		ProgRouterLoader() : +			opts("CGI Prog Router options") +		{ +			opts +				("cgi.progRouter.routes", Options::value(&routingTable), +				 "Script file defining web service routes") +				; +		} + +		const Options * options() const +		{ +			return &opts; +		} + +		void onBefore() +		{ +			routingTable.onBefore(); +		} + +		static RoutingTable routingTable; + +	private: +		Options opts; +}; + +RoutingTable ProgRouterLoader::routingTable; + +SimpleMessageException(UriElementNotFound); + +class ProgRouter : public Router { +	public: +		ProgRouter(const std::string & p) : +			path(p) { +		} +		std::string route() const { +			return ProgRouterLoader::routingTable.present(path, vars); +		} +		bool isDefault() const { +			return false; +		} +		VariableType routeParameter(const VariableType & vp) const { +			return safeMapLookup<UriElementNotFound>(vars, vp); +		} +		unsigned int parameterCount() const { +			return vars.size(); +		} +		void present(const MultiRowSetPresenter * p) const { +			p->addNewArray("uriElem", true); +			boost::filesystem::path y(path); +			boost::filesystem::path::iterator pathPart = y.begin(); +			while(++pathPart != y.end()) { +				p->addNamedValue("uriElem", pathPart->string()); +			} +			p->finishArray(true); +			p->addNewArray("uriParam", true); +			BOOST_FOREACH(const auto & v, vars) { +				p->addNamedValue("uriParam", v.first); +			} +			p->finishArray(true); +		} + +	private: +		const std::string path; +		mutable VarMap vars; +}; + +DECLARE_CUSTOM_COMPONENT_LOADER("progRouter", ProgRouter, ProgRouterLoader, RouterLoader); diff --git a/project2/cgi/cgiRouter.h b/project2/cgi/cgiRouter.h new file mode 100644 index 0000000..dd9c0e6 --- /dev/null +++ b/project2/cgi/cgiRouter.h @@ -0,0 +1,20 @@ +#ifndef CGIROUTER_H +#define CGIROUTER_H + +#include <variables.h> +#include <scriptLoader.h> + +class MultiRowSetPresenter; + +class Router : public IntrusivePtrBase { +	public: +		virtual bool isDefault() const = 0; +		virtual std::string route() const = 0; +		virtual VariableType routeParameter(const VariableType & var) const = 0; +		virtual unsigned int parameterCount() const = 0; +		virtual void present(const MultiRowSetPresenter * p) const = 0; +}; +typedef GenLoader<Router, const std::string &> RouterLoader; + +#endif + diff --git a/project2/cgi/cgiSimpleRouter.cpp b/project2/cgi/cgiSimpleRouter.cpp new file mode 100644 index 0000000..a28cf1d --- /dev/null +++ b/project2/cgi/cgiSimpleRouter.cpp @@ -0,0 +1,55 @@ +#include "cgiEnvironment.h" +#include "scriptLoader.h" +#include "presenter.h" + +std::vector<std::string> +makeVector(const boost::filesystem::path & y) +{ +	std::vector<std::string> r; +	boost::filesystem::path::iterator p = y.begin(); +	p++; +	while(p != y.end()) { +		r.push_back((p++)->string()); +	} +	return r; +} + +class SimpleRouter : public Router { +	public: +		SimpleRouter(const std::string & p) : +			path(p), +			elems(makeVector(p)) { +		} +		std::string route() const { +			return path; +		} +		bool isDefault() const { +			return elems.empty(); +		} +		VariableType routeParameter(const VariableType & vp) const { +			unsigned int p = (int)vp; +			if (p >= elems.size()) { +				throw UriElementOutOfRange(p); +			} +			return elems[p]; +		} +		unsigned int parameterCount() const { +			return elems.size(); +		} +		void present(const MultiRowSetPresenter * p) const { +			p->addNewArray("uriElem", true); +			boost::filesystem::path y(path); +			boost::filesystem::path::iterator pathPart = y.begin(); +			while(++pathPart != y.end()) { +				p->addNamedValue("uriElem", pathPart->string()); +			} +			p->finishArray(true); +		} + +	private: +		const std::string path; +		std::vector<std::string> elems; +}; + +DECLARE_GENERIC_LOADER("simple", RouterLoader, SimpleRouter); + diff --git a/project2/cgi/cgiStageInitial.cpp b/project2/cgi/cgiStageInitial.cpp index 5abbbfb..1fe4820 100644 --- a/project2/cgi/cgiStageInitial.cpp +++ b/project2/cgi/cgiStageInitial.cpp @@ -3,20 +3,15 @@  #include "cgiEnvironment.h"  #include "exceptions.h" -StaticMessageException(EmptyRequestURL, "Request URL cannot be empty"); -  CgiApplicationEngine::NextStage  CgiApplicationEngine::InitialStage::run()  {  	const CgiEnvironment * e = env();  	if (e->getRequestMethod() == "POST") { -		if (e->elems.empty()) { -			throw EmptyRequestURL(); -		} -		return NextStage(new RequestStage(e->resolveScript(e->requestRoot, e->getRedirectURL(), false))); +		return NextStage(new RequestStage(e->resolveScript(e->requestRoot, e->router->route(), false)));  	}  	else { -		return NextStage(new PresentStage(e->resolveScript(e->presentRoot, e->elems.empty() ? e->defaultPresent : e->getRedirectURL(), false))); +		return NextStage(new PresentStage(e->resolveScript(e->presentRoot, e->router->isDefault() ? e->defaultPresent : e->router->route(), false)));  	}  } diff --git a/project2/common/environment.h b/project2/common/environment.h index accbb80..4daea74 100644 --- a/project2/common/environment.h +++ b/project2/common/environment.h @@ -21,7 +21,7 @@ class Environment {  		static const Environment * getCurrent(); -		virtual Glib::ustring getParamUri(unsigned int idx) const = 0; +		virtual Glib::ustring getParamUri(VariableType idx) const = 0;  		virtual unsigned int getParamUriCount() const = 0;  		virtual Glib::ustring getParamQuery(const std::string & idx) const = 0; diff --git a/project2/common/options.h b/project2/common/options.h index 62a38fb..a28b5f8 100644 --- a/project2/common/options.h +++ b/project2/common/options.h @@ -35,7 +35,6 @@ namespace std {  class Options {  	public:  		class Target; -		template <typename T> class TypedTarget;  		enum TargetState { Default = 1, Global = 2, Platform = 3 };  		class Target : public IntrusivePtrBase { @@ -58,14 +57,19 @@ class Options {  				mutable TargetState ts;  		}; -		template <typename T> class TypedTarget : public InstanceTarget { +		template <typename T, typename D = T> class TypedTarget : public InstanceTarget {  			public: +				TypedTarget(T * t, const D & d) : +					target(t), +					defValue(d) { +				}  				TypedTarget(T * t) : -					target(t) { +					target(t), +					defValue(T()) {  				}  				void reset() const {  					ts = Default; -					*target = T(); +					*target = defValue;  				}  				void assign(const Glib::ustring & value) const {  					doAssign(value); @@ -81,6 +85,7 @@ class Options {  				void doAssign(const Glib::ustring & value, typename boost::enable_if<std::is_assignable<T, Glib::ustring>, dummy>::type = 0) const {  					*target = value;  				} +				D defValue;  		};  		template <typename T> class TypedTarget<std::vector<T> > : public InstanceTarget { @@ -100,20 +105,6 @@ class Options {  				VofT * target;  		}; -		template <typename T, typename D> class DefaultTypedTarget : public TypedTarget<T> { -			public: -				DefaultTypedTarget(T * t, const D & d) : -					TypedTarget<T>(t), -					defValue(d) { -				} -				void reset() const { -					InstanceTarget::ts = Default; -					*TypedTarget<T>::target = defValue; -				} -			private: -				T defValue; -		}; -  		class Option : public IntrusivePtrBase {  			public:  				virtual void reset() const = 0; @@ -138,7 +129,12 @@ class Options {  		template <typename T, typename D>  		static  		TargetPtr value(T * t, const D & d) { -			return new DefaultTypedTarget<T, D>(t, d); +			return new TypedTarget<T>(t, d); +		} +		template <typename T, typename D> +		static +		TargetPtr valueConvert(T * t, const D & d) { +			return new TypedTarget<T, D>(t, d);  		}  		void reset() const; diff --git a/project2/common/typePointer.h b/project2/common/typePointer.h deleted file mode 100644 index 95bf28a..0000000 --- a/project2/common/typePointer.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef TYPEPOINTER_H -#define TYPEPOINTER_H - -template <typename T, typename P = typename boost::intrusive_ptr<T>> -class TypePointer : public P { -	public: -		TypePointer() { } -		TypePointer(const std::string &) { } - -		TypePointer & operator=(const std::string & value) { -			P::operator=(GenLoader<T>::createNew(value)); -			return *this; -		} -}; - -#endif - diff --git a/project2/common/variables-moduri.cpp b/project2/common/variables-moduri.cpp index 041141f..81b8698 100644 --- a/project2/common/variables-moduri.cpp +++ b/project2/common/variables-moduri.cpp @@ -9,13 +9,13 @@ class VariableUri : public VariableImplDyn {  	public:  		VariableUri(ScriptNodePtr e) :  			VariableImplDyn(e), -			index(e->value("index").as<int32_t>()) +			index(e, "index")  		{  		}  		VariableType value() const  		{  			try { -				return ApplicationEngine::getCurrent()->env()->getParamUri(index); +				return ApplicationEngine::getCurrent()->env()->getParamUri(index());  			}  			catch (UriElementOutOfRange) {  				if (!defaultValue) { @@ -25,7 +25,7 @@ class VariableUri : public VariableImplDyn {  			}  		}  	private: -		unsigned int index; +		Variable index;  };  DECLARE_COMPONENT_LOADER("uri", VariableUri, VariableLoader); diff --git a/project2/console/consoleEnvironment.cpp b/project2/console/consoleEnvironment.cpp index 8f4465c..69f17cd 100644 --- a/project2/console/consoleEnvironment.cpp +++ b/project2/console/consoleEnvironment.cpp @@ -63,9 +63,10 @@ ConsoleEnvironment::~ConsoleEnvironment()  }  Glib::ustring -ConsoleEnvironment::getParamUri(unsigned int idx) const +ConsoleEnvironment::getParamUri(VariableType _idx) const  { -	if (idx < uriParams.size()) { +	int32_t idx = _idx; +	if (idx < (int32_t)uriParams.size()) {  		return uriParams[idx];  	}  	throw UriElementOutOfRange(idx); diff --git a/project2/console/consoleEnvironment.h b/project2/console/consoleEnvironment.h index 6d57d3c..6ce2d75 100644 --- a/project2/console/consoleEnvironment.h +++ b/project2/console/consoleEnvironment.h @@ -17,7 +17,7 @@ class ConsoleEnvironment : public Environment {  		virtual ~ConsoleEnvironment(); -		Glib::ustring getParamUri(unsigned int idx) const; +		Glib::ustring getParamUri(VariableType idx) const;  		unsigned int getParamUriCount() const;  		Glib::ustring getParamQuery(const std::string & idx) const;  		std::string getServerName() const; diff --git a/project2/xml/xmlPresenter.cpp b/project2/xml/xmlPresenter.cpp index 2d72561..45836a2 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", "")), +	ContentPresenter(e->value("contenttype", "text/xml")),  	SourceOf<xmlpp::Document>(e, os),  	SourceOf<_xmlDoc>(e, os),  	SourceOf<boost::shared_ptr<xmlpp::Document> >(e, os),  | 
