diff options
-rw-r--r-- | icespider/common/Jamfile.jam | 4 | ||||
-rw-r--r-- | icespider/common/pathparts.cpp (renamed from icespider/core/paths.cpp) | 10 | ||||
-rw-r--r-- | icespider/common/pathparts.h (renamed from icespider/core/paths.h) | 16 | ||||
-rw-r--r-- | icespider/common/routes.ice | 9 | ||||
-rw-r--r-- | icespider/compile/routeCompiler.cpp | 72 | ||||
-rw-r--r-- | icespider/core/core.cpp | 2 | ||||
-rw-r--r-- | icespider/core/irouteHandler.h | 2 | ||||
-rw-r--r-- | icespider/unittests/testApp.cpp | 25 | ||||
-rw-r--r-- | icespider/unittests/testCompile.cpp | 4 | ||||
-rw-r--r-- | icespider/unittests/testRoutes.json | 24 |
10 files changed, 136 insertions, 32 deletions
diff --git a/icespider/common/Jamfile.jam b/icespider/common/Jamfile.jam index 081ebd1..c06ff0c 100644 --- a/icespider/common/Jamfile.jam +++ b/icespider/common/Jamfile.jam @@ -1,6 +1,9 @@ +lib adhocutil : : : : <include>/usr/include/adhocutil ; + lib icespider-common : [ glob-tree *.ice *.cpp : bin ] : + <library>adhocutil <library>..//pthread <library>..//Ice <library>..//IceUtil @@ -8,5 +11,6 @@ lib icespider-common : <library>..//pthread <library>..//Ice <library>..//IceUtil + <include>. ; diff --git a/icespider/core/paths.cpp b/icespider/common/pathparts.cpp index f4bad0e..d7581b3 100644 --- a/icespider/core/paths.cpp +++ b/icespider/common/pathparts.cpp @@ -1,5 +1,6 @@ -#include "paths.h" +#include "pathparts.h" #include <boost/algorithm/string/split.hpp> +#include <boost/algorithm/string/trim.hpp> namespace ba = boost::algorithm; @@ -12,7 +13,7 @@ namespace IceSpider { for (auto pi = ba::make_split_iterator(relp, ba::first_finder("/", ba::is_equal())); pi != decltype(pi)(); ++pi) { std::string pp(pi->begin(), pi->end()); if (pp.front() == '{' && pp.back() == '}') { - parts.push_back(PathPartPtr(new PathParameter())); + parts.push_back(PathPartPtr(new PathParameter(pp))); } else { parts.push_back(PathPartPtr(new PathLiteral(pp))); @@ -38,6 +39,11 @@ namespace IceSpider { return value == v; } + PathParameter::PathParameter(const std::string & s) : + name(boost::algorithm::trim_copy_if(s, ispunct)) + { + } + bool PathParameter::matches(const std::string &) const { diff --git a/icespider/core/paths.h b/icespider/common/pathparts.h index 0999593..0720af0 100644 --- a/icespider/core/paths.h +++ b/icespider/common/pathparts.h @@ -4,30 +4,34 @@ #include <vector> #include <string> #include <memory> +#include <visibility.h> namespace IceSpider { - - class PathPart { + class DLL_PUBLIC PathPart { public: virtual bool matches(const std::string &) const = 0; }; typedef std::shared_ptr<PathPart> PathPartPtr; - class PathLiteral : public PathPart { + class DLL_PUBLIC PathLiteral : public PathPart { public: PathLiteral(const std::string & v); bool matches(const std::string &) const; - private: const std::string value; }; - class PathParameter : public PathPart { + class DLL_PUBLIC PathParameter : public PathPart { public: + PathParameter(const std::string &); + bool matches(const std::string &) const; + + const std::string name; }; - class Path { + + class DLL_PUBLIC Path { public: typedef std::vector<PathPartPtr> PathParts; diff --git a/icespider/common/routes.ice b/icespider/common/routes.ice index 01bed51..0e64692 100644 --- a/icespider/common/routes.ice +++ b/icespider/common/routes.ice @@ -7,15 +7,20 @@ module UserIceSpider { }; class Parameter { string name; - ParameterSource source; + ParameterSource source = URL; optional(0) string key; bool isOptional = false; + ["slicer:name:default"] + optional(1) string defaultExpr; + + ["slicer:ignore"] + bool hasUserSource; }; sequence<Parameter> Parameters; class Route { string name; string path; - HttpMethod method; + HttpMethod method = GET; string operation; Parameters params; }; diff --git a/icespider/compile/routeCompiler.cpp b/icespider/compile/routeCompiler.cpp index 9c6c59d..b28231e 100644 --- a/icespider/compile/routeCompiler.cpp +++ b/icespider/compile/routeCompiler.cpp @@ -1,4 +1,5 @@ #include "routeCompiler.h" +#include <pathparts.h> #include <slicer/slicer.h> #include <slicer/modelPartsTypes.h> #include <Slice/Preprocessor.h> @@ -84,9 +85,21 @@ namespace IceSpider { if (defined != r->params.end()) { auto d = *defined; if (!d->key) d->key = d->name; - continue; } - r->params.push_back(new UserIceSpider::Parameter(p->name(), UserIceSpider::ParameterSource::URL, p->name(), false)); + else { + r->params.push_back(new UserIceSpider::Parameter(p->name(), UserIceSpider::ParameterSource::URL, p->name(), false, IceUtil::Optional<std::string>(), false)); + defined = --r->params.end(); + } + auto d = *defined; + if (d->source == UserIceSpider::ParameterSource::URL) { + IceSpider::Path path(r->path); + d->hasUserSource = std::find_if(path.parts.begin(), path.parts.end(), [d](const auto & pp) { + if (auto par = dynamic_cast<PathParameter *>(pp.get())) { + return par->name == d->key; + } + return false; + }) != path.parts.end(); + } } } } @@ -211,8 +224,15 @@ namespace IceSpider { fprintbf(3, output, "%s() :\n", r->name); fprintbf(4, output, "IceSpider::IRouteHandler(UserIceSpider::HttpMethod::%s, \"%s\")", methodName, r->path); for (const auto & p : r->params) { - fprintf(output, ",\n"); - fprintbf(4, output, "_pn_%s(\"%s\")", p->name, *p->key); + if (p->hasUserSource) { + fprintf(output, ",\n"); + fprintbf(4, output, "_pn_%s(\"%s\")", p->name, *p->key); + } + if (p->defaultExpr) { + fprintf(output, ",\n"); + fprintbf(4, output, "_pd_%s(%s)", + p->name, p->defaultExpr.get()); + } } fprintf(output, "\n"); fprintbf(3, output, "{\n"); @@ -221,15 +241,23 @@ namespace IceSpider { fprintbf(3, output, "{\n"); auto o = findOperation(r, units); for (const auto & p : r->params) { - 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(0, output, " /\n"); - fprintbf(5, output, " [this]() { return requiredParameterNotFound<%s>(\"%s\", _pn_%s); }", - Slice::typeToString(ip->type()), getEnumString(p->source), p->name); + 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(0, output, " /\n"); + if (p->defaultExpr) { + fprintbf(5, output, " [this]() { return _pd_%s; }", + p->name); + } + else { + fprintbf(5, output, " [this]() { return requiredParameterNotFound<%s>(\"%s\", _pn_%s); }", + Slice::typeToString(ip->type()), getEnumString(p->source), p->name); + } + } + fprintbf(0, output, ");\n"); } - fprintbf(0, output, ");\n"); } fprintbf(4, output, "auto prx = getProxy<%s>(request);\n", proxyName); if (o->returnsData()) { @@ -239,7 +267,15 @@ namespace IceSpider { fprintbf(4, output, "prx->%s(", operation); } for (const auto & p : o->parameters()) { - fprintbf(output, "_p_%s, ", p->name()); + auto rp = *std::find_if(r->params.begin(), r->params.end(), [p](const auto & rp) { + return rp->name == p->name(); + }); + if (rp->hasUserSource) { + fprintbf(output, "_p_%s, ", p->name()); + } + else { + fprintbf(output, "_pd_%s, ", p->name()); + } } fprintbf(output, "request->getContext())"); if (o->returnsData()) { @@ -252,7 +288,15 @@ namespace IceSpider { fprintbf(3, output, "}\n\n"); fprintbf(2, output, "private:\n"); for (const auto & p : r->params) { - fprintbf(3, output, "const std::string _pn_%s;\n", p->name); + if (p->hasUserSource) { + 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; }); + fprintbf(3, output, "const %s _pd_%s;\n", + Slice::typeToString(ip->type()), p->name); + + } } fprintbf(1, output, "};\n\n"); } diff --git a/icespider/core/core.cpp b/icespider/core/core.cpp index 9f87bda..5509580 100644 --- a/icespider/core/core.cpp +++ b/icespider/core/core.cpp @@ -51,7 +51,7 @@ namespace IceSpider { if (!path.empty()) { ba::split(pathparts, path, ba::is_any_of("/"), ba::token_compress_off); } - if (pathparts.size() > mroutes.size()) { + if (pathparts.size() >= mroutes.size()) { // Not found error return NULL; } diff --git a/icespider/core/irouteHandler.h b/icespider/core/irouteHandler.h index 911c1b4..32513ae 100644 --- a/icespider/core/irouteHandler.h +++ b/icespider/core/irouteHandler.h @@ -3,7 +3,7 @@ #include "ihttpRequest.h" #include "util.h" -#include "paths.h" +#include <pathparts.h> #include <routes.h> #include <plugins.h> #include <visibility.h> diff --git a/icespider/unittests/testApp.cpp b/icespider/unittests/testApp.cpp index 1e9562b..b5af516 100644 --- a/icespider/unittests/testApp.cpp +++ b/icespider/unittests/testApp.cpp @@ -12,7 +12,7 @@ using namespace UserIceSpider; BOOST_AUTO_TEST_CASE( testLoadConfiguration ) { - BOOST_REQUIRE_EQUAL(4, AdHoc::PluginManager::getDefault()->getAll<IceSpider::IRouteHandler>().size()); + BOOST_REQUIRE_EQUAL(6, AdHoc::PluginManager::getDefault()->getAll<IceSpider::IRouteHandler>().size()); } BOOST_FIXTURE_TEST_SUITE(c, IceSpider::Core); @@ -23,8 +23,8 @@ BOOST_AUTO_TEST_CASE( testCoreSettings ) BOOST_REQUIRE_EQUAL(4, routes[HttpMethod::GET].size()); BOOST_REQUIRE_EQUAL(1, routes[HttpMethod::GET][0].size()); BOOST_REQUIRE_EQUAL(0, routes[HttpMethod::GET][1].size()); - BOOST_REQUIRE_EQUAL(0, routes[HttpMethod::GET][2].size()); - BOOST_REQUIRE_EQUAL(1, routes[HttpMethod::GET][3].size()); + BOOST_REQUIRE_EQUAL(1, routes[HttpMethod::GET][2].size()); + BOOST_REQUIRE_EQUAL(2, routes[HttpMethod::GET][3].size()); BOOST_REQUIRE_EQUAL(1, routes[HttpMethod::HEAD].size()); BOOST_REQUIRE_EQUAL(2, routes[HttpMethod::POST].size()); BOOST_REQUIRE_EQUAL(0, routes[HttpMethod::POST][0].size()); @@ -44,7 +44,7 @@ class TestRequest : public IceSpider::IHttpRequest { path(p) { } - + std::string getRequestPath() const override { return path; @@ -108,6 +108,12 @@ BOOST_AUTO_TEST_CASE( testFindRoutes ) TestRequest requestGetItem(this, HttpMethod::GET, "/view/something/something"); BOOST_REQUIRE(findRoute(&requestGetItem)); + TestRequest requestGetItemParam(this, HttpMethod::GET, "/item/something/1234"); + BOOST_REQUIRE(findRoute(&requestGetItemParam)); + + TestRequest requestGetItemDefault(this, HttpMethod::GET, "/item/something"); + BOOST_REQUIRE(findRoute(&requestGetItemDefault)); + TestRequest requestGetItemLong(this, HttpMethod::GET, "/view/something/something/extra"); BOOST_REQUIRE(!findRoute(&requestGetItemLong)); @@ -167,6 +173,17 @@ BOOST_AUTO_TEST_CASE( testCallMethods ) 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); diff --git a/icespider/unittests/testCompile.cpp b/icespider/unittests/testCompile.cpp index 4325c16..26fc458 100644 --- a/icespider/unittests/testCompile.cpp +++ b/icespider/unittests/testCompile.cpp @@ -28,7 +28,7 @@ BOOST_AUTO_TEST_CASE( testLoadConfiguration ) rc.applyDefaults(cfg, u); BOOST_REQUIRE_EQUAL("common", cfg->name); - BOOST_REQUIRE_EQUAL(4, cfg->routes.size()); + BOOST_REQUIRE_EQUAL(6, cfg->routes.size()); BOOST_REQUIRE_EQUAL("index", cfg->routes[0]->name); BOOST_REQUIRE_EQUAL("/", cfg->routes[0]->path); @@ -85,7 +85,7 @@ BOOST_AUTO_TEST_CASE( testLoad ) BOOST_TEST_INFO(dlerror()); BOOST_REQUIRE(lib); - BOOST_REQUIRE_EQUAL(4, AdHoc::PluginManager::getDefault()->getAll<IceSpider::IRouteHandler>().size()); + BOOST_REQUIRE_EQUAL(6, AdHoc::PluginManager::getDefault()->getAll<IceSpider::IRouteHandler>().size()); // smoke test (block ensure dlclose dones't cause segfault) { auto route = AdHoc::PluginManager::getDefault()->get<IceSpider::IRouteHandler>("common::index"); diff --git a/icespider/unittests/testRoutes.json b/icespider/unittests/testRoutes.json index b766f31..4ad8cc3 100644 --- a/icespider/unittests/testRoutes.json +++ b/icespider/unittests/testRoutes.json @@ -36,6 +36,30 @@ "source": "Body" } ] + }, + { + "name": "defaultItem", + "path": "/item/{s}", + "method": "GET", + "operation": "TestIceSpider.TestApi.withParams", + "params": [ + { + "name": "i", + "default": "1234" + } + ] + }, + { + "name": "itemWithDefault", + "path": "/item/{s}/{i}", + "method": "GET", + "operation": "TestIceSpider.TestApi.withParams", + "params": [ + { + "name": "i", + "default": "1234" + } + ] } ], "slices": [ |