# HG changeset patch # User Sebastien Jodogne # Date 1403876002 -7200 # Node ID 886652370ff2fb0d04d23d40ed682fb615d1a92d # Parent d724ac031080a2045a94dc2c29faee01afa07e7c accelerating REST API matching diff -r d724ac031080 -r 886652370ff2 Core/RestApi/RestApiPath.cpp --- a/Core/RestApi/RestApiPath.cpp Fri Jun 27 13:58:02 2014 +0200 +++ b/Core/RestApi/RestApiPath.cpp Fri Jun 27 15:33:22 2014 +0200 @@ -33,6 +33,8 @@ #include "../PrecompiledHeaders.h" #include "RestApiPath.h" +#include "../OrthancException.h" + #include namespace Orthanc @@ -89,6 +91,8 @@ UriComponents& trailing, const UriComponents& uri) const { + assert(uri_.size() == components_.size()); + if (uri.size() < uri_.size()) { return false; @@ -135,4 +139,42 @@ UriComponents trailing; return Match(components, trailing, uri); } + + + bool RestApiPath::IsWildcardLevel(size_t level) const + { + assert(uri_.size() == components_.size()); + + if (level >= uri_.size()) + { + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + + return uri_[level].length() == 0; + } + + const std::string& RestApiPath::GetWildcardName(size_t level) const + { + assert(uri_.size() == components_.size()); + + if (!IsWildcardLevel(level)) + { + throw OrthancException(ErrorCode_BadParameterType); + } + + return components_[level]; + } + + const std::string& RestApiPath::GetLevelName(size_t level) const + { + assert(uri_.size() == components_.size()); + + if (IsWildcardLevel(level)) + { + throw OrthancException(ErrorCode_BadParameterType); + } + + return uri_[level]; + } } + diff -r d724ac031080 -r 886652370ff2 Core/RestApi/RestApiPath.h --- a/Core/RestApi/RestApiPath.h Fri Jun 27 13:58:02 2014 +0200 +++ b/Core/RestApi/RestApiPath.h Fri Jun 27 15:33:22 2014 +0200 @@ -59,5 +59,22 @@ const UriComponents& uri) const; bool Match(const UriComponents& uri) const; + + size_t GetLevelCount() const + { + return uri_.size(); + } + + bool IsWildcardLevel(size_t level) const; + + bool IsUniversalTrailing() const + { + return hasTrailing_; + } + + const std::string& GetWildcardName(size_t level) const; + + const std::string& GetLevelName(size_t level) const; + }; } diff -r d724ac031080 -r 886652370ff2 Core/Toolbox.cpp --- a/Core/Toolbox.cpp Fri Jun 27 13:58:02 2014 +0200 +++ b/Core/Toolbox.cpp Fri Jun 27 15:33:22 2014 +0200 @@ -284,6 +284,28 @@ } + void Toolbox::TruncateUri(UriComponents& target, + const UriComponents& source, + size_t fromLevel) + { + target.clear(); + + if (source.size() > fromLevel) + { + target.resize(source.size() - fromLevel); + + size_t j = 0; + for (size_t i = fromLevel; i < source.size(); i++, j++) + { + target[j] = source[i]; + } + + assert(j == target.size()); + } + } + + + bool Toolbox::IsChildUri(const UriComponents& baseUri, const UriComponents& testedUri) { diff -r d724ac031080 -r 886652370ff2 Core/Toolbox.h --- a/Core/Toolbox.h Fri Jun 27 13:58:02 2014 +0200 +++ b/Core/Toolbox.h Fri Jun 27 15:33:22 2014 +0200 @@ -73,6 +73,10 @@ void SplitUriComponents(UriComponents& components, const std::string& uri); + void TruncateUri(UriComponents& target, + const UriComponents& source, + size_t fromLevel); + bool IsChildUri(const UriComponents& baseUri, const UriComponents& testedUri); diff -r d724ac031080 -r 886652370ff2 UnitTestsSources/RestApi.cpp --- a/UnitTestsSources/RestApi.cpp Fri Jun 27 13:58:02 2014 +0200 +++ b/UnitTestsSources/RestApi.cpp Fri Jun 27 15:33:22 2014 +0200 @@ -138,6 +138,18 @@ ASSERT_TRUE(uri.Match(args, trail, "/coucou/moi/d/")); ASSERT_FALSE(uri.Match(args, trail, "/a/moi/d")); ASSERT_FALSE(uri.Match(args, trail, "/coucou/moi")); + + ASSERT_EQ(3u, uri.GetLevelCount()); + ASSERT_TRUE(uri.IsUniversalTrailing()); + + ASSERT_EQ("coucou", uri.GetLevelName(0)); + ASSERT_THROW(uri.GetWildcardName(0), OrthancException); + + ASSERT_EQ("abc", uri.GetWildcardName(1)); + ASSERT_THROW(uri.GetLevelName(1), OrthancException); + + ASSERT_EQ("d", uri.GetLevelName(2)); + ASSERT_THROW(uri.GetWildcardName(2), OrthancException); } { @@ -147,6 +159,18 @@ ASSERT_EQ(1u, args.size()); ASSERT_EQ(0u, trail.size()); ASSERT_EQ("moi", args["abc"]); + + ASSERT_EQ(3u, uri.GetLevelCount()); + ASSERT_FALSE(uri.IsUniversalTrailing()); + + ASSERT_EQ("coucou", uri.GetLevelName(0)); + ASSERT_THROW(uri.GetWildcardName(0), OrthancException); + + ASSERT_EQ("abc", uri.GetWildcardName(1)); + ASSERT_THROW(uri.GetLevelName(1), OrthancException); + + ASSERT_EQ("d", uri.GetLevelName(2)); + ASSERT_THROW(uri.GetWildcardName(2), OrthancException); } { @@ -157,5 +181,139 @@ ASSERT_EQ("a", trail[0]); ASSERT_EQ("b", trail[1]); ASSERT_EQ("c", trail[2]); + + ASSERT_EQ(0u, uri.GetLevelCount()); + ASSERT_TRUE(uri.IsUniversalTrailing()); } } + + + + + + +namespace Orthanc +{ + class RestApiResource + { + private: + struct Handlers + { + std::list getHandlers_; + std::list putHandlers_; + std::list postHandlers_; + std::list deleteHandlers_; + + void Register(RestApi::GetHandler handler) + { + getHandlers_.push_back(handler); + } + + void Register(RestApi::PutHandler handler) + { + putHandlers_.push_back(handler); + } + + void Register(RestApi::PostHandler handler) + { + postHandlers_.push_back(handler); + } + + void Register(RestApi::DeleteHandler handler) + { + deleteHandlers_.push_back(handler); + } + }; + + + typedef std::map Children; + + Children children_; + Children wildcardChildren_; + Handlers handlers_; + Handlers universalHandlers_; + + + static RestApiResource& AddChild(Children& children, + const std::string& name) + { + Children::iterator it = children.find(name); + + if (it == children.end()) + { + // Create new child + RestApiResource *child = new RestApiResource; + children[name] = child; + return *child; + } + else + { + return *it->second; + } + } + + + static void DeleteChildren(Children& children) + { + for (Children::iterator it = children.begin(); + it != children.end(); it++) + { + delete it->second; + } + } + + + + + template + void RegisterInternal(const RestApiPath& path, + Handler handler, + size_t level) + { + if (path.GetLevelCount() == level) + { + if (path.IsUniversalTrailing()) + { + universalHandlers_.Register(handler); + } + else + { + handlers_.Register(handler); + } + } + else if (path.IsWildcardLevel(level)) + { + AddChild(wildcardChildren_, path.GetWildcardName(level)); + } + } + + + public: + ~RestApiResource() + { + DeleteChildren(children_); + DeleteChildren(wildcardChildren_); + } + + void Register(const RestApiPath& path, + RestApi::GetHandler handler) + { + RegisterInternal(path, handler, 0); + } + }; + +} + + + +static void Toto(RestApi::GetCall& get) +{ +} + + +TEST(RestApi, RestApiResource) +{ + RestApiResource root; + + root.Register(RestApiPath("/hello/world/test"), Toto); +} diff -r d724ac031080 -r 886652370ff2 UnitTestsSources/UnitTestsMain.cpp --- a/UnitTestsSources/UnitTestsMain.cpp Fri Jun 27 13:58:02 2014 +0200 +++ b/UnitTestsSources/UnitTestsMain.cpp Fri Jun 27 15:33:22 2014 +0200 @@ -212,7 +212,7 @@ TEST(Uri, SplitUriComponents) { - UriComponents c; + UriComponents c, d; Toolbox::SplitUriComponents(c, "/cou/hello/world"); ASSERT_EQ(3u, c.size()); ASSERT_EQ("cou", c[0]); @@ -253,6 +253,37 @@ } +TEST(Uri, Truncate) +{ + UriComponents c, d; + Toolbox::SplitUriComponents(c, "/cou/hello/world"); + + Toolbox::TruncateUri(d, c, 0); + ASSERT_EQ(3u, d.size()); + ASSERT_EQ("cou", d[0]); + ASSERT_EQ("hello", d[1]); + ASSERT_EQ("world", d[2]); + + Toolbox::TruncateUri(d, c, 1); + ASSERT_EQ(2u, d.size()); + ASSERT_EQ("hello", d[0]); + ASSERT_EQ("world", d[1]); + + Toolbox::TruncateUri(d, c, 2); + ASSERT_EQ(1u, d.size()); + ASSERT_EQ("world", d[0]); + + Toolbox::TruncateUri(d, c, 3); + ASSERT_EQ(0u, d.size()); + + Toolbox::TruncateUri(d, c, 4); + ASSERT_EQ(0u, d.size()); + + Toolbox::TruncateUri(d, c, 5); + ASSERT_EQ(0u, d.size()); +} + + TEST(Uri, Child) { UriComponents c1; Toolbox::SplitUriComponents(c1, "/hello/world");