# HG changeset patch # User Sebastien Jodogne # Date 1403097733 -7200 # Node ID 7d88f3f4a3b38362947ceb6c69901dc8fa16ccf5 # Parent 1b92ce45cc8dc83ebc7a844f41df7b4aa036ed21 refactoring IsServedUri, answer PNG images, regular expression groups diff -r 1b92ce45cc8d -r 7d88f3f4a3b3 Core/HttpServer/EmbeddedResourceHttpHandler.cpp --- a/Core/HttpServer/EmbeddedResourceHttpHandler.cpp Wed Jun 18 14:02:02 2014 +0200 +++ b/Core/HttpServer/EmbeddedResourceHttpHandler.cpp Wed Jun 18 15:22:13 2014 +0200 @@ -51,12 +51,6 @@ } - bool EmbeddedResourceHttpHandler::IsServedUri(const UriComponents& uri) - { - return Toolbox::IsChildUri(baseUri_, uri); - } - - bool EmbeddedResourceHttpHandler::Handle( HttpOutput& output, HttpMethod method, @@ -65,6 +59,12 @@ const Arguments& arguments, const std::string&) { + if (!Toolbox::IsChildUri(baseUri_, uri)) + { + // This URI is not served by this handler + return false; + } + if (method != HttpMethod_Get) { output.SendMethodNotAllowedError("GET"); diff -r 1b92ce45cc8d -r 7d88f3f4a3b3 Core/HttpServer/EmbeddedResourceHttpHandler.h --- a/Core/HttpServer/EmbeddedResourceHttpHandler.h Wed Jun 18 14:02:02 2014 +0200 +++ b/Core/HttpServer/EmbeddedResourceHttpHandler.h Wed Jun 18 15:22:13 2014 +0200 @@ -50,8 +50,6 @@ const std::string& baseUri, EmbeddedResources::DirectoryResourceId resourceId); - virtual bool IsServedUri(const UriComponents& uri); - virtual bool Handle( HttpOutput& output, HttpMethod method, diff -r 1b92ce45cc8d -r 7d88f3f4a3b3 Core/HttpServer/FilesystemHttpHandler.cpp --- a/Core/HttpServer/FilesystemHttpHandler.cpp Wed Jun 18 14:02:02 2014 +0200 +++ b/Core/HttpServer/FilesystemHttpHandler.cpp Wed Jun 18 15:22:13 2014 +0200 @@ -120,12 +120,6 @@ } - bool FilesystemHttpHandler::IsServedUri(const UriComponents& uri) - { - return Toolbox::IsChildUri(pimpl_->baseUri_, uri); - } - - bool FilesystemHttpHandler::Handle( HttpOutput& output, HttpMethod method, @@ -134,6 +128,12 @@ const Arguments& arguments, const std::string&) { + if (!Toolbox::IsChildUri(pimpl_->baseUri_, uri)) + { + // This URI is not served by this handler + return false; + } + if (method != HttpMethod_Get) { output.SendMethodNotAllowedError("GET"); diff -r 1b92ce45cc8d -r 7d88f3f4a3b3 Core/HttpServer/FilesystemHttpHandler.h --- a/Core/HttpServer/FilesystemHttpHandler.h Wed Jun 18 14:02:02 2014 +0200 +++ b/Core/HttpServer/FilesystemHttpHandler.h Wed Jun 18 15:22:13 2014 +0200 @@ -52,8 +52,6 @@ FilesystemHttpHandler(const std::string& baseUri, const std::string& root); - virtual bool IsServedUri(const UriComponents& uri); - virtual bool Handle( HttpOutput& output, HttpMethod method, diff -r 1b92ce45cc8d -r 7d88f3f4a3b3 Core/HttpServer/HttpHandler.h --- a/Core/HttpServer/HttpHandler.h Wed Jun 18 14:02:02 2014 +0200 +++ b/Core/HttpServer/HttpHandler.h Wed Jun 18 15:22:13 2014 +0200 @@ -50,8 +50,6 @@ { } - virtual bool IsServedUri(const UriComponents& uri) = 0; - virtual bool Handle(HttpOutput& output, HttpMethod method, const UriComponents& uri, diff -r 1b92ce45cc8d -r 7d88f3f4a3b3 Core/HttpServer/MongooseServer.cpp --- a/Core/HttpServer/MongooseServer.cpp Wed Jun 18 14:02:02 2014 +0200 +++ b/Core/HttpServer/MongooseServer.cpp Wed Jun 18 15:22:13 2014 +0200 @@ -255,22 +255,6 @@ - void MongooseServer::FindHandlers(std::list& result, - const UriComponents& forUri) const - { - for (Handlers::const_iterator it = - handlers_.begin(); it != handlers_.end(); ++it) - { - if ((*it)->IsServedUri(forUri)) - { - result.push_back(*it); - } - } - } - - - - static PostDataStatus ReadBody(std::string& postData, struct mg_connection *connection, const HttpHandler::Arguments& headers) @@ -702,20 +686,15 @@ } - // Locate the candidate handlers for this URI + // Loop over the candidate handlers for this URI LOG(INFO) << EnumerationToString(method) << " " << Toolbox::FlattenUri(uri); - std::list handlers; - that->FindHandlers(handlers, uri); - bool found = false; bool isError = false; HttpStatus errorStatus; std::string errorDescription; - - // Loop over the candidate handlers for this URI - for (std::list::const_iterator - it = handlers.begin(); it != handlers.end() && !found; it++) + for (MongooseServer::Handlers::const_iterator it = + that->GetHandlers().begin(); it != that->GetHandlers().end(); ++it) { try { diff -r 1b92ce45cc8d -r 7d88f3f4a3b3 Core/HttpServer/MongooseServer.h --- a/Core/HttpServer/MongooseServer.h Wed Jun 18 14:02:02 2014 +0200 +++ b/Core/HttpServer/MongooseServer.h Wed Jun 18 15:22:13 2014 +0200 @@ -59,12 +59,14 @@ class MongooseServer { + public: + typedef std::list Handlers; + private: // http://stackoverflow.com/questions/311166/stdauto-ptr-or-boostshared-ptr-for-pimpl-idiom struct PImpl; boost::shared_ptr pimpl_; - typedef std::list Handlers; Handlers handlers_; typedef std::set RegisteredUsers; @@ -139,11 +141,13 @@ void ClearHandlers(); - void FindHandlers(std::list& result, - const UriComponents& forUri) const; - ChunkStore& GetChunkStore(); bool IsValidBasicHttpAuthentication(const std::string& basic) const; + + const Handlers& GetHandlers() const + { + return handlers_; + } }; } diff -r 1b92ce45cc8d -r 7d88f3f4a3b3 Core/RestApi/RestApi.cpp --- a/Core/RestApi/RestApi.cpp Wed Jun 18 14:02:02 2014 +0200 +++ b/Core/RestApi/RestApi.cpp Wed Jun 18 15:22:13 2014 +0200 @@ -172,13 +172,6 @@ } } - bool RestApi::IsServedUri(const UriComponents& uri) - { - return (IsGetAccepted(uri) || - IsPutAccepted(uri) || - IsPostAccepted(uri) || - IsDeleteAccepted(uri)); - } bool RestApi::Handle(HttpOutput& output, HttpMethod method, @@ -187,6 +180,16 @@ const Arguments& getArguments, const std::string& postData) { + if (!IsGetAccepted(uri) && + !IsPutAccepted(uri) && + !IsPostAccepted(uri) && + !IsDeleteAccepted(uri)) + { + // This URI is not served by this handler + return false; + } + + bool ok = false; RestApiOutput restOutput(output); RestApiPath::Components components; diff -r 1b92ce45cc8d -r 7d88f3f4a3b3 Core/RestApi/RestApi.h --- a/Core/RestApi/RestApi.h Wed Jun 18 14:02:02 2014 +0200 +++ b/Core/RestApi/RestApi.h Wed Jun 18 15:22:13 2014 +0200 @@ -271,8 +271,6 @@ ~RestApi(); - virtual bool IsServedUri(const UriComponents& uri); - virtual bool Handle(HttpOutput& output, HttpMethod method, const UriComponents& uri, diff -r 1b92ce45cc8d -r 7d88f3f4a3b3 Plugins/Engine/PluginsHttpHandler.cpp --- a/Plugins/Engine/PluginsHttpHandler.cpp Wed Jun 18 14:02:02 2014 +0200 +++ b/Plugins/Engine/PluginsHttpHandler.cpp Wed Jun 18 15:22:13 2014 +0200 @@ -35,6 +35,7 @@ #include "../../Core/OrthancException.h" #include "../../Core/Toolbox.h" #include "../../Core/HttpServer/HttpOutput.h" +#include "../../Core/ImageFormats/PngWriter.h" #include #include @@ -47,11 +48,6 @@ typedef std::list Callbacks; Callbacks callbacks_; - OrthancPluginRestCallback currentCallback_; - - PImpl() : currentCallback_(NULL) - { - } }; @@ -71,24 +67,6 @@ } - bool PluginsHttpHandler::IsServedUri(const UriComponents& uri) - { - pimpl_->currentCallback_ = NULL; - std::string tmp = Toolbox::FlattenUri(uri); - - for (PImpl::Callbacks::const_iterator it = pimpl_->callbacks_.begin(); - it != pimpl_->callbacks_.end(); it++) - { - if (boost::regex_match(tmp, *(it->first))) - { - pimpl_->currentCallback_ = it->second; - return true; - } - } - - return false; - } - bool PluginsHttpHandler::Handle(HttpOutput& output, HttpMethod method, const UriComponents& uri, @@ -97,6 +75,39 @@ const std::string& postData) { std::string flatUri = Toolbox::FlattenUri(uri); + OrthancPluginRestCallback callback = NULL; + + std::vector groups; + std::vector cgroups; + + bool found = false; + for (PImpl::Callbacks::const_iterator it = pimpl_->callbacks_.begin(); + it != pimpl_->callbacks_.end() && !found; it++) + { + boost::cmatch what; + if (boost::regex_match(flatUri.c_str(), what, *(it->first))) + { + callback = it->second; + + if (what.size() > 1) + { + groups.resize(what.size() - 1); + cgroups.resize(what.size() - 1); + for (size_t i = 1; i < what.size(); i++) + { + groups[i - 1] = what[i]; + cgroups[i - 1] = groups[i - 1].c_str(); + } + } + + found = true; + } + } + + if (!found) + { + return false; + } LOG(INFO) << "Delegating HTTP request to plugin for URI: " << flatUri; @@ -140,6 +151,8 @@ } + request.groupValues = (cgroups.size() ? &cgroups[0] : NULL); + request.groupCount = cgroups.size(); request.getCount = getArguments.size(); request.body = (postData.size() ? &postData[0] : NULL); request.bodySize = postData.size(); @@ -150,10 +163,10 @@ request.getValues = &getValues[0]; } - assert(pimpl_->currentCallback_ != NULL); - int32_t error = (*pimpl_->currentCallback_) (reinterpret_cast(&output), - flatUri.c_str(), - &request); + assert(callback != NULL); + int32_t error = callback(reinterpret_cast(&output), + flatUri.c_str(), + &request); if (error < 0) { @@ -175,36 +188,6 @@ bool PluginsHttpHandler::InvokeService(OrthancPluginService service, const void* parameters) { - - - /*void PluginsManager::RegisterRestCallback(const OrthancPluginContext* context, - const char* pathRegularExpression, - OrthancPluginRestCallback callback) - { - LOG(INFO) << "Plugin has registered a REST callback on: " << pathRegularExpression; - PluginsManager* manager = reinterpret_cast(context->pluginsManager); - manager->restCallbacks_.push_back(std::make_pair(pathRegularExpression, callback)); - }*/ - - - /*static void AnswerBuffer(OrthancPluginRestOutput* output, - const char* answer, - uint32_t answerSize, - const char* mimeType) - { - HttpOutput* translatedOutput = reinterpret_cast(output); - translatedOutput->AnswerBufferWithContentType(answer, answerSize, mimeType); - }*/ - - - - /*for (PluginsManager::RestCallbacks::const_iterator - it = manager.GetRestCallbacks().begin(); it != manager.GetRestCallbacks().end(); ++it) - { - pimpl_->callbacks_.push_back(std::make_pair(new boost::regex(it->first), it->second)); - }*/ - - switch (service) { case OrthancPluginService_RegisterRestCallback: @@ -229,6 +212,52 @@ return true; } + case OrthancPluginService_CompressAndAnswerPngImage: + { + const _OrthancPluginCompressAndAnswerPngImageParams& p = + *reinterpret_cast(parameters); + + HttpOutput* translatedOutput = reinterpret_cast(p.output); + + PixelFormat format; + switch (p.format) + { + case OrthancPluginPixelFormat_Grayscale8: + format = PixelFormat_Grayscale8; + break; + + case OrthancPluginPixelFormat_Grayscale16: + format = PixelFormat_Grayscale16; + break; + + case OrthancPluginPixelFormat_SignedGrayscale16: + format = PixelFormat_SignedGrayscale16; + break; + + case OrthancPluginPixelFormat_RGB24: + format = PixelFormat_RGB24; + break; + + case OrthancPluginPixelFormat_RGBA32: + format = PixelFormat_RGBA32; + break; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + + ImageAccessor accessor; + accessor.AssignReadOnly(format, p.width, p.height, p.pitch, p.buffer); + + PngWriter writer; + std::string png; + writer.WriteToMemory(png, accessor); + + translatedOutput->AnswerBufferWithContentType(png, "image/png"); + + return true; + } + default: return false; } diff -r 1b92ce45cc8d -r 7d88f3f4a3b3 Plugins/Engine/PluginsHttpHandler.h --- a/Plugins/Engine/PluginsHttpHandler.h Wed Jun 18 14:02:02 2014 +0200 +++ b/Plugins/Engine/PluginsHttpHandler.h Wed Jun 18 15:22:13 2014 +0200 @@ -52,8 +52,6 @@ virtual ~PluginsHttpHandler(); - virtual bool IsServedUri(const UriComponents& uri); - virtual bool Handle(HttpOutput& output, HttpMethod method, const UriComponents& uri, diff -r 1b92ce45cc8d -r 7d88f3f4a3b3 Plugins/Engine/PluginsManager.cpp --- a/Plugins/Engine/PluginsManager.cpp Wed Jun 18 14:02:02 2014 +0200 +++ b/Plugins/Engine/PluginsManager.cpp Wed Jun 18 15:22:13 2014 +0200 @@ -155,6 +155,7 @@ } PluginsManager* that = reinterpret_cast(context->pluginsManager); + bool error = false; for (std::list::iterator it = that->serviceProviders_.begin(); @@ -170,10 +171,19 @@ catch (OrthancException&) { // This service provider has failed, go to the next + error = true; } } - LOG(ERROR) << "Plugin invoking unknown service " << service; + if (error) + { + LOG(ERROR) << "Exception when dealing with service " << service; + } + else + { + LOG(ERROR) << "Plugin invoking unknown service " << service; + } + return -1; } diff -r 1b92ce45cc8d -r 7d88f3f4a3b3 Plugins/OrthancCPlugin/OrthancCPlugin.h --- a/Plugins/OrthancCPlugin/OrthancCPlugin.h Wed Jun 18 14:02:02 2014 +0200 +++ b/Plugins/OrthancCPlugin/OrthancCPlugin.h Wed Jun 18 15:22:13 2014 +0200 @@ -123,6 +123,10 @@ { OrthancPluginHttpMethod method; + /* Groups of the regular expression */ + const char* const* groupValues; + uint32_t groupCount; + /* For GET requests */ const char* const* getKeys; const char* const* getValues; @@ -144,11 +148,58 @@ OrthancPluginService_RegisterRestCallback = 1000, /* Sending answers to REST calls */ - OrthancPluginService_AnswerBuffer = 2000 + OrthancPluginService_AnswerBuffer = 2000, + OrthancPluginService_CompressAndAnswerPngImage = 2001 } OrthancPluginService; + /** + * The memory layout of the pixels of an image. + **/ + typedef enum + { + /** + * @brief Graylevel 8bpp image. + * + * The image is graylevel. Each pixel is unsigned and stored in + * one byte. + **/ + OrthancPluginPixelFormat_Grayscale8 = 1, + + /** + * @brief Graylevel, unsigned 16bpp image. + * + * The image is graylevel. Each pixel is unsigned and stored in + * two bytes. + **/ + OrthancPluginPixelFormat_Grayscale16 = 2, + + /** + * @brief Graylevel, signed 16bpp image. + * + * The image is graylevel. Each pixel is signed and stored in two + * bytes. + **/ + OrthancPluginPixelFormat_SignedGrayscale16 = 3, + + /** + * @brief Color image in RGB24 format. + * + * This format describes a color image. The pixels are stored in 3 + * consecutive bytes. The memory layout is RGB. + **/ + OrthancPluginPixelFormat_RGB24 = 4, + + /** + * @brief Color image in RGBA32 format. + * + * This format describes a color image. The pixels are stored in 4 + * consecutive bytes. The memory layout is RGBA. + **/ + OrthancPluginPixelFormat_RGBA32 = 5 + } OrthancPluginPixelFormat; + typedef struct _OrthancPluginRestOutput_t OrthancPluginRestOutput; @@ -168,22 +219,6 @@ } OrthancPluginContext; - typedef struct - { - const char* pathRegularExpression; - OrthancPluginRestCallback callback; - } _OrthancPluginRestCallbackParams; - - - typedef struct - { - OrthancPluginRestOutput* output; - const char* answer; - uint32_t answerSize; - const char* mimeType; - } _OrthancPluginAnswerBufferParams; - - ORTHANC_PLUGIN_INLINE void OrthancPluginLogError( OrthancPluginContext* context, const char* str) @@ -208,6 +243,13 @@ } + typedef struct + { + const char* pathRegularExpression; + OrthancPluginRestCallback callback; + } _OrthancPluginRestCallbackParams; + + ORTHANC_PLUGIN_INLINE void OrthancPluginRegisterRestCallback( OrthancPluginContext* context, const char* pathRegularExpression, @@ -220,6 +262,14 @@ } + typedef struct + { + OrthancPluginRestOutput* output; + const char* answer; + uint32_t answerSize; + const char* mimeType; + } _OrthancPluginAnswerBufferParams; + ORTHANC_PLUGIN_INLINE void OrthancPluginAnswerBuffer( OrthancPluginContext* context, OrthancPluginRestOutput* output, @@ -236,6 +286,36 @@ } + typedef struct + { + OrthancPluginRestOutput* output; + OrthancPluginPixelFormat format; + uint32_t width; + uint32_t height; + uint32_t pitch; + const void* buffer; + } _OrthancPluginCompressAndAnswerPngImageParams; + + ORTHANC_PLUGIN_INLINE void OrthancPluginCompressAndAnswerPngImage( + OrthancPluginContext* context, + OrthancPluginRestOutput* output, + OrthancPluginPixelFormat format, + uint32_t width, + uint32_t height, + uint32_t pitch, + const void* buffer) + { + _OrthancPluginCompressAndAnswerPngImageParams params; + params.output = output; + params.format = format; + params.width = width; + params.height = height; + params.pitch = pitch; + params.buffer = buffer; + context->InvokeService(context, OrthancPluginService_CompressAndAnswerPngImage, ¶ms); + } + + /** Each plugin must define 4 functions, whose signature are: diff -r 1b92ce45cc8d -r 7d88f3f4a3b3 Resources/OrthancPlugin.doxygen --- a/Resources/OrthancPlugin.doxygen Wed Jun 18 14:02:02 2014 +0200 +++ b/Resources/OrthancPlugin.doxygen Wed Jun 18 15:22:13 2014 +0200 @@ -545,7 +545,7 @@ # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. -MAX_INITIALIZER_LINES = 30 +MAX_INITIALIZER_LINES = 0 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the diff -r 1b92ce45cc8d -r 7d88f3f4a3b3 Resources/Samples/Plugins/Basic/Plugin.c --- a/Resources/Samples/Plugins/Basic/Plugin.c Wed Jun 18 14:02:02 2014 +0200 +++ b/Resources/Samples/Plugins/Basic/Plugin.c Wed Jun 18 15:22:13 2014 +0200 @@ -33,9 +33,9 @@ static OrthancPluginContext* context = NULL; -ORTHANC_PLUGINS_API int32_t Callback(OrthancPluginRestOutput* output, - const char* url, - const OrthancPluginHttpRequest* request) +ORTHANC_PLUGINS_API int32_t Callback1(OrthancPluginRestOutput* output, + const char* url, + const OrthancPluginHttpRequest* request) { char buffer[1024]; uint32_t i; @@ -51,10 +51,42 @@ OrthancPluginLogInfo(context, buffer); } + printf("** %d\n", request->groupCount); + for (i = 0; i < request->groupCount; i++) + { + printf("** [%s]\n", request->groupValues[i]); + } + return 1; } +ORTHANC_PLUGINS_API int32_t Callback2(OrthancPluginRestOutput* output, + const char* url, + const OrthancPluginHttpRequest* request) +{ + /** + * Answer with a sample 16bpp image. + **/ + + uint16_t buffer[256 * 256]; + uint32_t x, y, value; + + value = 0; + for (y = 0; y < 256; y++) + { + for (x = 0; x < 256; x++, value++) + { + buffer[value] = value; + } + } + + OrthancPluginCompressAndAnswerPngImage(context, output, OrthancPluginPixelFormat_Grayscale16, + 256, 256, sizeof(uint16_t) * 256, buffer); + return 0; +} + + ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* c) { char info[1024]; @@ -65,7 +97,8 @@ sprintf(info, "The version of Orthanc is '%s'", context->orthancVersion); OrthancPluginLogInfo(context, info); - OrthancPluginRegisterRestCallback(context, "/plu.*/hello", Callback); + OrthancPluginRegisterRestCallback(context, "/(plu.*)/hello", Callback1); + OrthancPluginRegisterRestCallback(context, "/plu.*/image", Callback2); return 0; }