From e548772e83997fd2b1cdf1473b68e912ee986018 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 26 Jun 2016 12:40:30 +0100 Subject: URL parameters by index internally, not key --- icespider/compile/routeCompiler.cpp | 31 ++++++++++++++++++++++++++----- icespider/core/core.cpp | 10 +--------- icespider/core/ihttpRequest.cpp | 18 ++++++++++++++---- icespider/core/ihttpRequest.h | 6 +++--- icespider/core/irouteHandler.h | 8 +++++--- icespider/fcgi/cgiRequestBase.cpp | 22 ++++++++++++---------- icespider/fcgi/cgiRequestBase.h | 6 +++--- icespider/unittests/testApp.cpp | 30 ++++++++++++------------------ 8 files changed, 76 insertions(+), 55 deletions(-) diff --git a/icespider/compile/routeCompiler.cpp b/icespider/compile/routeCompiler.cpp index b28231e..8064946 100644 --- a/icespider/compile/routeCompiler.cpp +++ b/icespider/compile/routeCompiler.cpp @@ -226,7 +226,21 @@ namespace IceSpider { for (const auto & p : r->params) { if (p->hasUserSource) { fprintf(output, ",\n"); - fprintbf(4, output, "_pn_%s(\"%s\")", p->name, *p->key); + if (p->source == UserIceSpider::ParameterSource::URL) { + IceSpider::Path path(r->path); + unsigned int idx = -1; + for (const auto & pp : path.parts) { + if (auto par = dynamic_cast(pp.get())) { + if (par->name == p->key) { + idx = &pp - &path.parts.front(); + } + } + }; + fprintbf(4, output, "_pi_%s(%d)", p->name, idx); + } + else { + fprintbf(4, output, "_pn_%s(\"%s\")", p->name, *p->key); + } } if (p->defaultExpr) { fprintf(output, ",\n"); @@ -243,9 +257,11 @@ namespace IceSpider { for (const auto & p : r->params) { if (p->hasUserSource) { auto ip = *std::find_if(o->parameters().begin(), o->parameters().end(), [p](const auto & ip) { return ip->name() == p->name; }); - fprintbf(4, output, "auto _p_%s(request->get%sParam<%s>(_pn_%s)", - p->name, getEnumString(p->source), Slice::typeToString(ip->type()), p->name); - if (!p->isOptional) { + fprintbf(4, output, "auto _p_%s(request->get%sParam<%s>(_p%c_%s)", + p->name, getEnumString(p->source), Slice::typeToString(ip->type()), + p->source == UserIceSpider::ParameterSource::URL ? 'i' : 'n', + p->name); + if (!p->isOptional && p->source != UserIceSpider::ParameterSource::URL) { fprintbf(0, output, " /\n"); if (p->defaultExpr) { fprintbf(5, output, " [this]() { return _pd_%s; }", @@ -289,7 +305,12 @@ namespace IceSpider { fprintbf(2, output, "private:\n"); for (const auto & p : r->params) { if (p->hasUserSource) { - fprintbf(3, output, "const std::string _pn_%s;\n", p->name); + if (p->source == UserIceSpider::ParameterSource::URL) { + fprintbf(3, output, "const unsigned int _pi_%s;\n", p->name); + } + else { + fprintbf(3, output, "const std::string _pn_%s;\n", p->name); + } } if (p->defaultExpr) { auto ip = *std::find_if(o->parameters().begin(), o->parameters().end(), [p](const auto & ip) { return ip->name() == p->name; }); diff --git a/icespider/core/core.cpp b/icespider/core/core.cpp index 5509580..35af72f 100644 --- a/icespider/core/core.cpp +++ b/icespider/core/core.cpp @@ -1,10 +1,6 @@ #include "core.h" -#include -#include #include -namespace ba = boost::algorithm; - namespace IceSpider { Core::Core(int argc, char ** argv) { @@ -45,12 +41,8 @@ namespace IceSpider { const IRouteHandler * Core::findRoute(const IHttpRequest * request) const { - auto path = request->getRequestPath().substr(1); + auto & pathparts = request->getRequestPath(); const auto & mroutes = routes[request->getRequestMethod()]; - std::vector pathparts; - if (!path.empty()) { - ba::split(pathparts, path, ba::is_any_of("/"), ba::token_compress_off); - } if (pathparts.size() >= mroutes.size()) { // Not found error return NULL; diff --git a/icespider/core/ihttpRequest.cpp b/icespider/core/ihttpRequest.cpp index a352dca..0dd2aea 100644 --- a/icespider/core/ihttpRequest.cpp +++ b/icespider/core/ihttpRequest.cpp @@ -30,6 +30,16 @@ namespace IceSpider { "application/json", getOutputStream()); } + const std::string & + IHttpRequest::getURLParam(unsigned int idx) const + { + auto & url = getRequestPath(); + if (idx >= url.size()) { + throw std::runtime_error("Bad Url parameter index"); + } + return url[idx]; + } + template inline IceUtil::Optional optionalLexicalCast(const IceUtil::Optional & p) { @@ -46,14 +56,14 @@ namespace IceSpider { #define getParams(T) \ - template<> IceUtil::Optional IHttpRequest::getURLParam(const std::string & key) const { \ - return optionalLexicalCast(getURLParam(key)); } \ + template<> T IHttpRequest::getURLParam(unsigned int idx) const { \ + return boost::lexical_cast(getURLParam(idx)); } \ template<> IceUtil::Optional IHttpRequest::getQueryStringParam(const std::string & key) const { \ return optionalLexicalCast(getQueryStringParam(key)); } \ template<> IceUtil::Optional IHttpRequest::getHeaderParam(const std::string & key) const { \ return optionalLexicalCast(getHeaderParam(key)); } - template<> IceUtil::Optional IHttpRequest::getURLParam(const std::string & key) const { \ - return getURLParam(key); } + template<> std::string IHttpRequest::getURLParam(unsigned int idx) const { + return getURLParam(idx); } template<> IceUtil::Optional IHttpRequest::getQueryStringParam(const std::string & key) const { \ return getQueryStringParam(key); } template<> IceUtil::Optional IHttpRequest::getHeaderParam(const std::string & key) const { \ diff --git a/icespider/core/ihttpRequest.h b/icespider/core/ihttpRequest.h index 14dccda..c52ee46 100644 --- a/icespider/core/ihttpRequest.h +++ b/icespider/core/ihttpRequest.h @@ -17,10 +17,10 @@ namespace IceSpider { IHttpRequest(const Core *); Ice::Context getContext() const; - virtual std::string getRequestPath() const = 0; + virtual const std::vector & getRequestPath() const = 0; virtual UserIceSpider::HttpMethod getRequestMethod() const = 0; - virtual IceUtil::Optional getURLParam(const std::string &) const = 0; + const std::string & getURLParam(unsigned int) const; virtual IceUtil::Optional getQueryStringParam(const std::string &) const = 0; virtual IceUtil::Optional getHeaderParam(const std::string &) const = 0; virtual Slicer::DeserializerPtr getDeserializer() const; @@ -29,7 +29,7 @@ namespace IceSpider { virtual std::ostream & getOutputStream() const = 0; template - IceUtil::Optional getURLParam(const std::string & key) const; + T getURLParam(unsigned int) const; template IceUtil::Optional getBodyParam(const std::string &) const { diff --git a/icespider/core/irouteHandler.h b/icespider/core/irouteHandler.h index 32513ae..969ca86 100644 --- a/icespider/core/irouteHandler.h +++ b/icespider/core/irouteHandler.h @@ -7,6 +7,7 @@ #include #include #include +#include namespace IceSpider { class DLL_PUBLIC IRouteHandler : public AdHoc::AbstractPluginImplementation, public Path { @@ -17,10 +18,11 @@ namespace IceSpider { const UserIceSpider::HttpMethod method; protected: - template - inline T requiredParameterNotFound(const char *, const std::string & key) const + template + inline T requiredParameterNotFound(const char *, const K & key) const { - throw std::runtime_error("Required parameter not found: " + key); + throw std::runtime_error("Required parameter not found: " + + boost::lexical_cast(key)); } Ice::ObjectPrx getProxy(IHttpRequest *, const char *) const; diff --git a/icespider/fcgi/cgiRequestBase.cpp b/icespider/fcgi/cgiRequestBase.cpp index 97a71fc..ec9836b 100644 --- a/icespider/fcgi/cgiRequestBase.cpp +++ b/icespider/fcgi/cgiRequestBase.cpp @@ -1,6 +1,7 @@ #include "cgiRequestBase.h" #include #include +#include #include namespace ba = boost::algorithm; @@ -26,6 +27,15 @@ namespace IceSpider { void CgiRequestBase::initialize() { + namespace ba = boost::algorithm; + auto path = (optionalLookup("REDIRECT_URL", envmap) / + [this]() { return optionalLookup("SCRIPT_NAME", envmap); } / + [this]() -> std::string { throw std::runtime_error("Couldn't determine request path"); }) + .substr(1); + if (!path.empty()) { + ba::split(pathmap, path, ba::is_any_of("/"), ba::token_compress_off); + } + auto qs = envmap.find("QUERY_STRING"); if (qs != envmap.end()) { auto start = std::get<0>(qs->second); @@ -58,12 +68,10 @@ namespace IceSpider { return std::string(std::get<0>(i->second), std::get<1>(i->second)); } - std::string + const std::vector & 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"); }; + return pathmap; } UserIceSpider::HttpMethod @@ -72,12 +80,6 @@ namespace IceSpider { return UserIceSpider::HttpMethod::GET; } - IceUtil::Optional - CgiRequestBase::getURLParam(const std::string & key) const - { - return optionalLookup(key, pathmap); - } - IceUtil::Optional CgiRequestBase::getQueryStringParam(const std::string & key) const { diff --git a/icespider/fcgi/cgiRequestBase.h b/icespider/fcgi/cgiRequestBase.h index 8a6d207..8f5b613 100644 --- a/icespider/fcgi/cgiRequestBase.h +++ b/icespider/fcgi/cgiRequestBase.h @@ -15,14 +15,14 @@ namespace IceSpider { typedef std::tuple Env; typedef std::map VarMap; + typedef std::vector UrlMap; CgiRequestBase(IceSpider::Core * c, char ** env); void addenv(char *); void initialize(); - std::string getRequestPath() const override; + const std::vector & getRequestPath() const override; UserIceSpider::HttpMethod getRequestMethod() const override; - IceUtil::Optional getURLParam(const std::string & key) const override; IceUtil::Optional getQueryStringParam(const std::string & key) const override; IceUtil::Optional getHeaderParam(const std::string & key) const override; @@ -30,7 +30,7 @@ namespace IceSpider { VarMap envmap; VarMap qsmap; - VarMap pathmap; + UrlMap pathmap; }; } diff --git a/icespider/unittests/testApp.cpp b/icespider/unittests/testApp.cpp index b5af516..cf14c81 100644 --- a/icespider/unittests/testApp.cpp +++ b/icespider/unittests/testApp.cpp @@ -7,6 +7,8 @@ #include #include #include +#include +#include using namespace UserIceSpider; @@ -40,14 +42,18 @@ class TestRequest : public IceSpider::IHttpRequest { public: TestRequest(const IceSpider::Core * c, HttpMethod m, const std::string & p) : IHttpRequest(c), - method(m), - path(p) + method(m) { + namespace ba = boost::algorithm; + auto path = p.substr(1); + if (!path.empty()) { + ba::split(url, path, ba::is_any_of("/"), ba::token_compress_off); + } } - std::string getRequestPath() const override + const std::vector & getRequestPath() const override { - return path; + return url; } HttpMethod getRequestMethod() const override @@ -55,11 +61,6 @@ class TestRequest : public IceSpider::IHttpRequest { return method; } - IceUtil::Optional getURLParam(const std::string & key) const override - { - return AdHoc::safeMapLookup(url, key); - } - IceUtil::Optional getQueryStringParam(const std::string & key) const override { return AdHoc::safeMapLookup(qs, key); @@ -81,14 +82,14 @@ class TestRequest : public IceSpider::IHttpRequest { } typedef std::map MapVars; - MapVars url; + typedef std::vector UrlVars; + UrlVars url; MapVars qs; MapVars hdr; mutable std::stringstream input; mutable std::stringstream output; const HttpMethod method; - const std::string path; }; BOOST_AUTO_TEST_CASE( testFindRoutes ) @@ -168,29 +169,22 @@ BOOST_AUTO_TEST_CASE( testCallMethods ) BOOST_REQUIRE_EQUAL(requestGetIndex.output.str(), "200 OK\r\n\r\n{\"value\":\"index\"}"); TestRequest requestGetItem(this, HttpMethod::GET, "/view/something/1234"); - requestGetItem.url["s"] = "something"; - requestGetItem.url["i"] = "1234"; process(&requestGetItem); BOOST_REQUIRE_EQUAL(requestGetItem.output.str(), "200 OK\r\n\r\n{\"value\":\"withParams\"}"); TestRequest requestGetItemGiven(this, HttpMethod::GET, "/item/something/1234"); - requestGetItemGiven.url["s"] = "something"; - requestGetItemGiven.url["i"] = "1234"; process(&requestGetItemGiven); BOOST_REQUIRE_EQUAL(requestGetItemGiven.output.str(), "200 OK\r\n\r\n{\"value\":\"withParams\"}"); TestRequest requestGetItemDefault(this, HttpMethod::GET, "/item/something"); - requestGetItemDefault.url["s"] = "something"; process(&requestGetItemDefault); BOOST_REQUIRE_EQUAL(requestGetItemDefault.output.str(), "200 OK\r\n\r\n{\"value\":\"withParams\"}"); TestRequest requestDeleteItem(this, HttpMethod::DELETE, "/some value"); - requestDeleteItem.url["s"] = "some value"; process(&requestDeleteItem); BOOST_REQUIRE_EQUAL(requestDeleteItem.output.str(), "200 OK\r\n\r\n"); TestRequest requestUpdateItem(this, HttpMethod::POST, "/1234"); - requestUpdateItem.url["id"] = "1234"; requestUpdateItem.hdr["Content-Type"] = "application/json"; requestUpdateItem.input << "{\"value\": \"some value\"}"; process(&requestUpdateItem); -- cgit v1.2.3