# HG changeset patch # User Sebastien Jodogne # Date 1404142900 -7200 # Node ID f1ff2a2f06cd558c94b3be454854e63aa48ef0bb # Parent 624f44047238243dbb144f9edebee7b479ecff3d use RestApiHierarchy inside RestApi diff -r 624f44047238 -r f1ff2a2f06cd Core/RestApi/RestApi.cpp --- a/Core/RestApi/RestApi.cpp Mon Jun 30 16:10:13 2014 +0200 +++ b/Core/RestApi/RestApi.cpp Mon Jun 30 17:41:40 2014 +0200 @@ -36,63 +36,89 @@ #include // To define "_exit()" under Windows #include +#include + namespace Orthanc { - bool RestApi::IsGetAccepted(const UriComponents& uri) + namespace { - for (GetHandlers::const_iterator it = getHandlers_.begin(); - it != getHandlers_.end(); ++it) + // Anonymous namespace to avoid clashes between compilation modules + class HttpHandlerVisitor : public RestApiHierarchy::IVisitor { - if (it->first->Match(uri)) + private: + RestApi& api_; + HttpOutput& output_; + HttpMethod method_; + const HttpHandler::Arguments& headers_; + const HttpHandler::Arguments& getArguments_; + const std::string& postData_; + + public: + HttpHandlerVisitor(RestApi& api, + HttpOutput& output, + HttpMethod method, + const HttpHandler::Arguments& headers, + const HttpHandler::Arguments& getArguments, + const std::string& postData) : + api_(api), + output_(output), + method_(method), + headers_(headers), + getArguments_(getArguments), + postData_(postData) { - return true; } - } + + virtual bool Visit(const RestApiHierarchy::Resource& resource, + const UriComponents& uri, + const HttpHandler::Arguments& components, + const UriComponents& trailing) + { + if (resource.HasHandler(method_)) + { + RestApiOutput output(output_); + + switch (method_) + { + case HttpMethod_Get: + { + RestApiGetCall call(output, api_, headers_, components, trailing, uri, getArguments_); + resource.Handle(call); + return true; + } - return false; + case HttpMethod_Post: + { + RestApiPostCall call(output, api_, headers_, components, trailing, uri, postData_); + resource.Handle(call); + return true; + } + + case HttpMethod_Delete: + { + RestApiDeleteCall call(output, api_, headers_, components, trailing, uri); + resource.Handle(call); + return true; + } + + case HttpMethod_Put: + { + RestApiPutCall call(output, api_, headers_, components, trailing, uri, postData_); + resource.Handle(call); + return true; + } + + default: + return false; + } + } + + return false; + } + }; } - bool RestApi::IsPutAccepted(const UriComponents& uri) - { - for (PutHandlers::const_iterator it = putHandlers_.begin(); - it != putHandlers_.end(); ++it) - { - if (it->first->Match(uri)) - { - return true; - } - } - return false; - } - - bool RestApi::IsPostAccepted(const UriComponents& uri) - { - for (PostHandlers::const_iterator it = postHandlers_.begin(); - it != postHandlers_.end(); ++it) - { - if (it->first->Match(uri)) - { - return true; - } - } - - return false; - } - - bool RestApi::IsDeleteAccepted(const UriComponents& uri) - { - for (DeleteHandlers::const_iterator it = deleteHandlers_.begin(); - it != deleteHandlers_.end(); ++it) - { - if (it->first->Match(uri)) - { - return true; - } - } - - return false; - } static void AddMethod(std::string& target, const std::string& method) @@ -103,51 +129,33 @@ target = method; } - std::string RestApi::GetAcceptedMethods(const UriComponents& uri) + static std::string MethodsToString(const std::set& methods) { std::string s; - if (IsGetAccepted(uri)) + if (methods.find(HttpMethod_Get) != methods.end()) + { AddMethod(s, "GET"); + } - if (IsPutAccepted(uri)) - AddMethod(s, "PUT"); + if (methods.find(HttpMethod_Post) != methods.end()) + { + AddMethod(s, "POST"); + } - if (IsPostAccepted(uri)) - AddMethod(s, "POST"); + if (methods.find(HttpMethod_Put) != methods.end()) + { + AddMethod(s, "PUT"); + } - if (IsDeleteAccepted(uri)) + if (methods.find(HttpMethod_Delete) != methods.end()) + { AddMethod(s, "DELETE"); + } return s; } - RestApi::~RestApi() - { - for (GetHandlers::iterator it = getHandlers_.begin(); - it != getHandlers_.end(); ++it) - { - delete it->first; - } - - for (PutHandlers::iterator it = putHandlers_.begin(); - it != putHandlers_.end(); ++it) - { - delete it->first; - } - - for (PostHandlers::iterator it = postHandlers_.begin(); - it != postHandlers_.end(); ++it) - { - delete it->first; - } - - for (DeleteHandlers::iterator it = deleteHandlers_.begin(); - it != deleteHandlers_.end(); ++it) - { - delete it->first; - } - } bool RestApi::Handle(HttpOutput& output, @@ -157,113 +165,60 @@ const Arguments& getArguments, const std::string& postData) { - if (!IsGetAccepted(uri) && - !IsPutAccepted(uri) && - !IsPostAccepted(uri) && - !IsDeleteAccepted(uri)) + HttpHandlerVisitor visitor(*this, output, method, headers, getArguments, postData); + + if (root_.LookupResource(uri, visitor)) { - // This URI is not served by this handler - return false; + return true; } - - bool ok = false; - RestApiOutput restOutput(output); - HttpHandler::Arguments components; - UriComponents trailing; - - if (method == HttpMethod_Get) - { - for (GetHandlers::const_iterator it = getHandlers_.begin(); - it != getHandlers_.end(); ++it) - { - if (it->first->Match(components, trailing, uri)) - { - //LOG(INFO) << "REST GET call on: " << Toolbox::FlattenUri(uri); - ok = true; - RestApiGetCall call(restOutput, *this, headers, components, trailing, uri, getArguments); - it->second(call); - } - } - } - else if (method == HttpMethod_Put) + Json::Value directory; + if (root_.GetDirectory(directory, uri)) { - for (PutHandlers::const_iterator it = putHandlers_.begin(); - it != putHandlers_.end(); ++it) - { - if (it->first->Match(components, trailing, uri)) - { - //LOG(INFO) << "REST PUT call on: " << Toolbox::FlattenUri(uri); - ok = true; - RestApiPutCall call(restOutput, *this, headers, components, trailing, uri, postData); - it->second(call); - } - } - } - else if (method == HttpMethod_Post) - { - for (PostHandlers::const_iterator it = postHandlers_.begin(); - it != postHandlers_.end(); ++it) - { - if (it->first->Match(components, trailing, uri)) - { - //LOG(INFO) << "REST POST call on: " << Toolbox::FlattenUri(uri); - ok = true; - RestApiPostCall call(restOutput, *this, headers, components, trailing, uri, postData); - it->second(call); - } - } - } - else if (method == HttpMethod_Delete) - { - for (DeleteHandlers::const_iterator it = deleteHandlers_.begin(); - it != deleteHandlers_.end(); ++it) - { - if (it->first->Match(components, trailing, uri)) - { - //LOG(INFO) << "REST DELETE call on: " << Toolbox::FlattenUri(uri); - ok = true; - RestApiDeleteCall call(restOutput, *this, headers, components, trailing, uri); - it->second(call); - } - } + RestApiOutput tmp(output); + tmp.AnswerJson(directory); + return true; } - if (!ok) + std::set methods; + root_.GetAcceptedMethods(methods, uri); + + if (methods.empty()) + { + return false; // This URI is not served by this REST API + } + else { LOG(INFO) << "REST method " << EnumerationToString(method) << " not allowed on: " << Toolbox::FlattenUri(uri); - output.SendMethodNotAllowedError(GetAcceptedMethods(uri)); + + output.SendMethodNotAllowedError(MethodsToString(methods)); + + return true; } - - return true; } void RestApi::Register(const std::string& path, RestApiGetCall::Handler handler) { root_.Register(path, handler); - getHandlers_.push_back(std::make_pair(new RestApiPath(path), handler)); } void RestApi::Register(const std::string& path, RestApiPutCall::Handler handler) { root_.Register(path, handler); - putHandlers_.push_back(std::make_pair(new RestApiPath(path), handler)); } void RestApi::Register(const std::string& path, RestApiPostCall::Handler handler) { root_.Register(path, handler); - postHandlers_.push_back(std::make_pair(new RestApiPath(path), handler)); } void RestApi::Register(const std::string& path, RestApiDeleteCall::Handler handler) { root_.Register(path, handler); - deleteHandlers_.push_back(std::make_pair(new RestApiPath(path), handler)); } } diff -r 624f44047238 -r f1ff2a2f06cd Core/RestApi/RestApi.h --- a/Core/RestApi/RestApi.h Mon Jun 30 16:10:13 2014 +0200 +++ b/Core/RestApi/RestApi.h Mon Jun 30 17:41:40 2014 +0200 @@ -43,30 +43,7 @@ private: RestApiHierarchy root_; - typedef std::list< std::pair > GetHandlers; - typedef std::list< std::pair > PutHandlers; - typedef std::list< std::pair > PostHandlers; - typedef std::list< std::pair > DeleteHandlers; - - GetHandlers getHandlers_; - PutHandlers putHandlers_; - PostHandlers postHandlers_; - DeleteHandlers deleteHandlers_; - - bool IsGetAccepted(const UriComponents& uri); - bool IsPutAccepted(const UriComponents& uri); - bool IsPostAccepted(const UriComponents& uri); - bool IsDeleteAccepted(const UriComponents& uri); - - std::string GetAcceptedMethods(const UriComponents& uri); - public: - RestApi() - { - } - - ~RestApi(); - virtual bool Handle(HttpOutput& output, HttpMethod method, const UriComponents& uri, diff -r 624f44047238 -r f1ff2a2f06cd Core/RestApi/RestApiHierarchy.cpp --- a/Core/RestApi/RestApiHierarchy.cpp Mon Jun 30 16:10:13 2014 +0200 +++ b/Core/RestApi/RestApiHierarchy.cpp Mon Jun 30 17:41:40 2014 +0200 @@ -203,11 +203,17 @@ IVisitor& visitor, size_t level) { - assert(uri.size() >= level); + if (uri.size() != 0 && + level > uri.size()) + { + return false; + } + UriComponents trailing; // Look for an exact match on the resource of interest - if (uri.size() == level) + if (uri.size() == 0 || + level == uri.size()) { if (!handlers_.IsEmpty() && visitor.Visit(handlers_, uri, components, trailing)) @@ -217,28 +223,30 @@ } - // Try and go down in the hierarchy, using an exact match for the child - Children::const_iterator child = children_.find(uri[level]); - if (child != children_.end()) + if (level < uri.size()) // A recursive call is possible { - if (child->second->LookupResource(components, uri, visitor, level + 1)) + // Try and go down in the hierarchy, using an exact match for the child + Children::const_iterator child = children_.find(uri[level]); + if (child != children_.end()) { - return true; + if (child->second->LookupResource(components, uri, visitor, level + 1)) + { + return true; + } } - } - - // Try and go down in the hierarchy, using wildcard rules for children - for (child = wildcardChildren_.begin(); - child != wildcardChildren_.end(); child++) - { - HttpHandler::Arguments subComponents = components; - subComponents[child->first] = uri[level]; + // Try and go down in the hierarchy, using wildcard rules for children + for (child = wildcardChildren_.begin(); + child != wildcardChildren_.end(); child++) + { + HttpHandler::Arguments subComponents = components; + subComponents[child->first] = uri[level]; - if (child->second->LookupResource(components, uri, visitor, level + 1)) - { - return true; - } + if (child->second->LookupResource(subComponents, uri, visitor, level + 1)) + { + return true; + } + } } @@ -354,49 +362,42 @@ void RestApiHierarchy::CreateSiteMap(Json::Value& target) const { - if (children_.size() == 0) - { - /*std::string s = " "; + target = Json::objectValue; + + /*std::string s = " "; if (handlers_.HasHandler(HttpMethod_Get)) { - s += "GET "; + s += "GET "; } if (handlers_.HasHandler(HttpMethod_Post)) { - s += "POST "; + s += "POST "; } if (handlers_.HasHandler(HttpMethod_Put)) { - s += "PUT "; + s += "PUT "; } if (handlers_.HasHandler(HttpMethod_Delete)) { - s += "DELETE "; + s += "DELETE "; } target = s;*/ - - target = Json::objectValue; - } - else + + for (Children::const_iterator it = children_.begin(); + it != children_.end(); it++) { - target = Json::objectValue; - - for (Children::const_iterator it = children_.begin(); - it != children_.end(); it++) - { - it->second->CreateSiteMap(target[it->first]); - } + it->second->CreateSiteMap(target[it->first]); } - /*for (Children::const_iterator it = wildcardChildren_.begin(); - it != wildcardChildren_.end(); it++) - { - it->second->CreateSiteMap(target["* (" + it->first + ")"]); - }*/ + for (Children::const_iterator it = wildcardChildren_.begin(); + it != wildcardChildren_.end(); it++) + { + it->second->CreateSiteMap(target["<" + it->first + ">"]); + } }