From ff096c8135f38a0dee72ed46706693d075d7a8e8 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 11 Nov 2016 11:14:41 +0000 Subject: Split implementation details (in CGI) of headers away from core functionality --- icespider/core/core.cpp | 62 ++++++++------------------------------- icespider/core/core.h | 9 +++--- icespider/core/ihttpRequest.cpp | 19 ++++-------- icespider/core/ihttpRequest.h | 5 ++-- icespider/fcgi/cgiCore.cpp | 51 ++++++++++++++++++++++++++++++++ icespider/fcgi/cgiCore.h | 21 +++++++++++++ icespider/fcgi/cgiRequestBase.cpp | 13 ++++++++ icespider/fcgi/cgiRequestBase.h | 3 ++ icespider/fcgi/main.cpp | 3 +- icespider/unittests/Jamfile.jam | 3 ++ icespider/unittests/testApp.cpp | 26 +++++++++++----- icespider/unittests/testFcgi.cpp | 4 +-- 12 files changed, 138 insertions(+), 81 deletions(-) create mode 100644 icespider/fcgi/cgiCore.cpp create mode 100644 icespider/fcgi/cgiCore.h diff --git a/icespider/core/core.cpp b/icespider/core/core.cpp index ab80b90..117c869 100644 --- a/icespider/core/core.cpp +++ b/icespider/core/core.cpp @@ -10,17 +10,6 @@ INSTANTIATEFACTORY(IceSpider::Plugin, Ice::CommunicatorPtr, Ice::PropertiesPtr); namespace IceSpider { const boost::filesystem::path Core::defaultConfig("config/ice.properties"); - static - bool - operator/=(const PathElements & pathparts, const IRouteHandler * r) - { - auto rpi = r->parts.begin(); - for (auto ppi = pathparts.begin(); ppi != pathparts.end(); ++ppi, ++rpi) { - if (!(*rpi)->matches(*ppi)) return false; - } - return true; - } - Core::Core(const Ice::StringSeq & args) { Ice::InitializationData id; @@ -34,18 +23,11 @@ namespace IceSpider { // Initialize routes for (const auto & rp : AdHoc::PluginManager::getDefault()->getAll()) { - auto r = rp->implementation()->create(this); - if (routes.size() <= r->pathElementCount()) { - routes.resize(r->pathElementCount() + 1); - } - auto & lroutes = routes[r->pathElementCount()]; - lroutes.push_back(r); - } - for (auto & l : routes) { - std::sort(l.begin(), l.end(), [](const auto & a, const auto & b) { - return a->path < b->path; - }); + allRoutes.push_back(rp->implementation()->create(this)); } + std::sort(allRoutes.begin(), allRoutes.end(), [](const auto & a, const auto & b) { + return a->path < b->path; + }); // Load plugins auto plugins = AdHoc::PluginManager::getDefault()->getAll(); if (!plugins.empty()) { @@ -69,21 +51,19 @@ namespace IceSpider { pluginAdapter->deactivate(); pluginAdapter->destroy(); } - // Initialize routes - for (auto l : routes) { - for (auto r : l) { - delete r; - } + // Terminate routes + for (auto r : allRoutes) { + delete r; } if (communicator) communicator->destroy(); } void - Core::process(IHttpRequest * request) const + Core::process(IHttpRequest * request, const IRouteHandler * route) const { try { - findRoute(request)->execute(request); + (route ? route : findRoute(request))->execute(request); } catch (const HttpException & he) { request->response(he.code, he.message); @@ -96,28 +76,10 @@ namespace IceSpider { } } - const IRouteHandler * - Core::findRoute(const IHttpRequest * request) const + const IceSpider::IRouteHandler * + Core::findRoute(const IceSpider::IHttpRequest *) const { - const auto & pathparts = request->getRequestPath(); - const auto method = request->getRequestMethod(); - if (pathparts.size() >= routes.size()) { - throw Http404_NotFound(); - } - const auto & routeSet = routes[pathparts.size()]; - bool match = false; - for (const auto & r : routeSet) { - if (pathparts /= r) { - if (r->method == method) { - return r; - } - match = true; - } - } - if (!match) { - throw Http404_NotFound(); - } - throw Http405_MethodNotAllowed(); + throw Http404_NotFound(); } Ice::ObjectPrx diff --git a/icespider/core/core.h b/icespider/core/core.h index 0627e74..d6aa173 100644 --- a/icespider/core/core.h +++ b/icespider/core/core.h @@ -11,14 +11,13 @@ namespace IceSpider { class DLL_PUBLIC Core { public: - typedef std::vector LengthRoutes; - typedef std::vector Routes; + typedef std::vector AllRoutes; Core(const Ice::StringSeq & = {}); ~Core(); - void process(IHttpRequest *) const; - const IRouteHandler * findRoute(const IHttpRequest *) const; + virtual const IRouteHandler * findRoute(const IHttpRequest *) const; + void process(IHttpRequest *, const IRouteHandler * = nullptr) const; Ice::ObjectPrx getProxy(const char * type) const; @@ -28,7 +27,7 @@ namespace IceSpider { return Interface::ProxyType::uncheckedCast(getProxy(typeid(Interface).name())); } - Routes routes; + AllRoutes allRoutes; Ice::CommunicatorPtr communicator; Ice::ObjectAdapterPtr pluginAdapter; diff --git a/icespider/core/ihttpRequest.cpp b/icespider/core/ihttpRequest.cpp index 1ca4c38..dea84e0 100644 --- a/icespider/core/ihttpRequest.cpp +++ b/icespider/core/ihttpRequest.cpp @@ -101,8 +101,8 @@ namespace IceSpider { const IceUtil::Optional & d, const IceUtil::Optional & p, bool s, IceUtil::Optional e) { - auto & o = getOutputStream(); - o << "Set-Cookie: " << XWwwFormUrlEncoded::urlencode(name) << + std::stringstream o; + o << XWwwFormUrlEncoded::urlencode(name) << '=' << XWwwFormUrlEncoded::urlencode(value); if (e) { char buf[45]; @@ -115,7 +115,7 @@ namespace IceSpider { if (d) o << "; domain=" << *d; if (p) o << "; path=" << *p; if (s) o << "; secure"; - o << "\r\n"; + setHeader("Set-Cookie", o.str()); } template @@ -127,17 +127,8 @@ namespace IceSpider { void IHttpRequest::responseRedirect(const std::string & url, const IceUtil::Optional & statusMsg) const { - getOutputStream() - << "Status: 303 " << (statusMsg ? *statusMsg : "Moved") << "\r\n" - << "Location: " << url << "\r\n" - << "\r\n"; - } - - void IHttpRequest::response(short statusCode, const std::string & statusMsg) const - { - getOutputStream() - << "Status: " << statusCode << " " << statusMsg << "\r\n" - << "\r\n"; + setHeader("Location", url); + response(303, (statusMsg ? *statusMsg : "Moved")); } diff --git a/icespider/core/ihttpRequest.h b/icespider/core/ihttpRequest.h index 0cd0f8b..d92d549 100644 --- a/icespider/core/ihttpRequest.h +++ b/icespider/core/ihttpRequest.h @@ -35,6 +35,7 @@ namespace IceSpider { virtual ContentTypeSerializer getSerializer(const IRouteHandler *) const; virtual std::istream & getInputStream() const = 0; virtual std::ostream & getOutputStream() const = 0; + virtual void setHeader(const std::string &, const std::string &) const = 0; template T getURLParam(unsigned int) const; @@ -70,12 +71,12 @@ namespace IceSpider { IceUtil::Optional getHeaderParam(const std::string & key) const; template IceUtil::Optional getCookieParam(const std::string & key) const; - void response(short, const std::string &) const; + virtual void response(short, const std::string &) const = 0; template void response(const IRouteHandler * route, const T & t) const { auto s = getSerializer(route); - getOutputStream() << "Content-Type: " << s.first.group << "/" << s.first.type << "\r\n"; + setHeader("Content-Type", s.first.group + "/" + s.first.type); response(200, "OK"); Slicer::SerializeAnyWith(t, s.second); } diff --git a/icespider/fcgi/cgiCore.cpp b/icespider/fcgi/cgiCore.cpp new file mode 100644 index 0000000..0adefab --- /dev/null +++ b/icespider/fcgi/cgiCore.cpp @@ -0,0 +1,51 @@ +#include "cgiCore.h" + +namespace IceSpider { + static + bool + operator/=(const PathElements & pathparts, const IRouteHandler * r) + { + auto rpi = r->parts.begin(); + for (auto ppi = pathparts.begin(); ppi != pathparts.end(); ++ppi, ++rpi) { + if (!(*rpi)->matches(*ppi)) return false; + } + return true; + } + + CgiCore::CgiCore(const Ice::StringSeq & opts) : + Core(opts) + { + for (const auto & r : allRoutes) { + if (routes.size() <= r->pathElementCount()) { + routes.resize(r->pathElementCount() + 1); + } + auto & lroutes = routes[r->pathElementCount()]; + lroutes.push_back(r); + } + } + + const IRouteHandler * + CgiCore::findRoute(const IHttpRequest * request) const + { + const auto & pathparts = request->getRequestPath(); + const auto method = request->getRequestMethod(); + if (pathparts.size() >= routes.size()) { + throw Http404_NotFound(); + } + const auto & routeSet = routes[pathparts.size()]; + bool match = false; + for (const auto & r : routeSet) { + if (pathparts /= r) { + if (r->method == method) { + return r; + } + match = true; + } + } + if (!match) { + throw Http404_NotFound(); + } + throw Http405_MethodNotAllowed(); + } +} + diff --git a/icespider/fcgi/cgiCore.h b/icespider/fcgi/cgiCore.h new file mode 100644 index 0000000..1915a4d --- /dev/null +++ b/icespider/fcgi/cgiCore.h @@ -0,0 +1,21 @@ +#ifndef ICESPIDER_CGI_CGICORE_H +#define ICESPIDER_CGI_CGICORE_H + +#include + +namespace IceSpider { + class CgiCore : public Core { + public: + typedef std::vector LengthRoutes; + typedef std::vector Routes; + + CgiCore(const Ice::StringSeq & = {}); + + const IRouteHandler * findRoute(const IHttpRequest *) const override; + + Routes routes; + }; +} + +#endif + diff --git a/icespider/fcgi/cgiRequestBase.cpp b/icespider/fcgi/cgiRequestBase.cpp index a773b07..e820e05 100644 --- a/icespider/fcgi/cgiRequestBase.cpp +++ b/icespider/fcgi/cgiRequestBase.cpp @@ -121,6 +121,19 @@ namespace IceSpider { return optionalLookup(("HTTP_" + boost::algorithm::to_upper_copy(key)).c_str(), envmap); } + void CgiRequestBase::response(short statusCode, const std::string & statusMsg) const + { + getOutputStream() + << "Status: " << statusCode << " " << statusMsg << "\r\n" + << "\r\n"; + } + + void + CgiRequestBase::setHeader(const std::string & header, const std::string & value) const + { + getOutputStream() << header << ": " << value << "\r\n"; + } + bool CgiRequestBase::cmp_str::operator()(char const * a, char const * b) const { diff --git a/icespider/fcgi/cgiRequestBase.h b/icespider/fcgi/cgiRequestBase.h index e613866..ec3d4dd 100644 --- a/icespider/fcgi/cgiRequestBase.h +++ b/icespider/fcgi/cgiRequestBase.h @@ -28,6 +28,9 @@ namespace IceSpider { OptionalString getCookieParam(const std::string & key) const override; OptionalString getEnv(const std::string & key) const override; + void response(short, const std::string &) const override; + void setHeader(const std::string &, const std::string &) const override; + private: static OptionalString optionalLookup(const std::string & key, const VarMap &); static OptionalString optionalLookup(const std::string & key, const StringMap &); diff --git a/icespider/fcgi/main.cpp b/icespider/fcgi/main.cpp index 2c543e1..4149cb2 100644 --- a/icespider/fcgi/main.cpp +++ b/icespider/fcgi/main.cpp @@ -1,6 +1,7 @@ #include #include "fcgiRequest.h" #include "cgiRequest.h" +#include "cgiCore.h" using namespace IceSpider; @@ -8,7 +9,7 @@ DLL_PUBLIC int main(int argc, char ** argv, char ** env) { - Core core; + CgiCore core; if (!FCGX_IsCGI()) { FCGX_Request request; diff --git a/icespider/unittests/Jamfile.jam b/icespider/unittests/Jamfile.jam index 8a0edff..ddc1e4a 100644 --- a/icespider/unittests/Jamfile.jam +++ b/icespider/unittests/Jamfile.jam @@ -64,6 +64,7 @@ run testApp.cpp base2.cpp testRoutes.json + ../fcgi/cgiCore.cpp : : config/ice.properties xslt/transform.xslt @@ -83,12 +84,14 @@ run test-api ../compile . + ../fcgi : testApp ; run testFcgi.cpp test-fcgi.ice ../fcgi/cgiRequestBase.cpp + ../fcgi/cgiCore.cpp : : : yes BOOST_TEST_DYN_LINK diff --git a/icespider/unittests/testApp.cpp b/icespider/unittests/testApp.cpp index de5e921..e42a5aa 100644 --- a/icespider/unittests/testApp.cpp +++ b/icespider/unittests/testApp.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include #include @@ -84,6 +84,18 @@ class TestRequest : public IHttpRequest { return output; } + void response(short statusCode, const std::string & statusMsg) const override + { + getOutputStream() + << "Status: " << statusCode << " " << statusMsg << "\r\n" + << "\r\n"; + } + + void setHeader(const std::string & header, const std::string & value) const override + { + getOutputStream() << header << ": " << value << "\r\n"; + } + typedef std::map MapVars; typedef std::vector UrlVars; UrlVars url; @@ -97,10 +109,10 @@ class TestRequest : public IHttpRequest { const HttpMethod method; }; -class CoreWithProps : public Core { +class CoreWithProps : public CgiCore { public: CoreWithProps() : - Core({ + CgiCore({ "--Custom.Prop=value" }) { @@ -119,10 +131,10 @@ BOOST_AUTO_TEST_CASE( properties ) BOOST_AUTO_TEST_SUITE_END(); -class CoreWithFileProps : public Core { +class CoreWithFileProps : public CgiCore { public: CoreWithFileProps() : - Core({ + CgiCore({ "--IceSpider.Config=config/custom.properties", "--Custom.Prop=value" }) @@ -144,7 +156,7 @@ BOOST_AUTO_TEST_CASE( properties ) BOOST_AUTO_TEST_SUITE_END(); -BOOST_FIXTURE_TEST_SUITE(defaultProps, Core); +BOOST_FIXTURE_TEST_SUITE(defaultProps, CgiCore); BOOST_AUTO_TEST_CASE( testCoreSettings ) { @@ -228,7 +240,7 @@ class TestSerice : public TestIceSpider::TestApi { } }; -class TestApp : public Core { +class TestApp : public CgiCore { public: TestApp() : adp(communicator->createObjectAdapterWithEndpoints("test", "default")) diff --git a/icespider/unittests/testFcgi.cpp b/icespider/unittests/testFcgi.cpp index bf8e442..2db9bcf 100644 --- a/icespider/unittests/testFcgi.cpp +++ b/icespider/unittests/testFcgi.cpp @@ -1,7 +1,7 @@ #define BOOST_TEST_MODULE TestApp #include -#include +#include #include #include #include @@ -87,7 +87,7 @@ namespace std { // LCOV_EXCL_STOP } -BOOST_FIXTURE_TEST_SUITE( CgiRequestBase, IceSpider::Core ); +BOOST_FIXTURE_TEST_SUITE( CgiRequestBase, IceSpider::CgiCore ); BOOST_AUTO_TEST_CASE( NoEnvironment ) { -- cgit v1.2.3