# HG changeset patch # User Sebastien Jodogne # Date 1617114842 -7200 # Node ID c8f444e8556d7820c91807c73cb123da89dd461b # Parent b7fe3494a53cff401144cc560fc9c662a7297876 new function in the plugin SDK: OrthancPluginCallRestApi() diff -r b7fe3494a53c -r c8f444e8556d NEWS --- a/NEWS Wed Mar 17 15:48:31 2021 +0100 +++ b/NEWS Tue Mar 30 16:34:02 2021 +0200 @@ -2,6 +2,13 @@ =============================== +Plugins +------- + +* New functions in the SDK: + - OrthancPluginCallRestApi() + + Version 1.9.1 (2021-02-25) ========================== diff -r b7fe3494a53c -r c8f444e8556d OrthancFramework/Sources/HttpServer/HttpToolbox.cpp --- a/OrthancFramework/Sources/HttpServer/HttpToolbox.cpp Wed Mar 17 15:48:31 2021 +0100 +++ b/OrthancFramework/Sources/HttpServer/HttpToolbox.cpp Tue Mar 30 16:34:02 2021 +0200 @@ -191,7 +191,7 @@ const std::string& uri, const Arguments& httpHeaders) { - return IHttpHandler::SimpleGet(result, handler, origin, uri, httpHeaders); + return (IHttpHandler::SimpleGet(result, NULL, handler, origin, uri, httpHeaders) == HttpStatus_200_Ok); } bool HttpToolbox::SimplePost(std::string& result, @@ -202,7 +202,8 @@ size_t bodySize, const Arguments& httpHeaders) { - return IHttpHandler::SimplePost(result, handler, origin, uri, bodyData, bodySize, httpHeaders); + return (IHttpHandler::SimplePost(result, NULL, handler, origin, uri, + bodyData, bodySize, httpHeaders) == HttpStatus_200_Ok); } bool HttpToolbox::SimplePut(std::string& result, @@ -213,7 +214,8 @@ size_t bodySize, const Arguments& httpHeaders) { - return IHttpHandler::SimplePut(result, handler, origin, uri, bodyData, bodySize, httpHeaders); + return (IHttpHandler::SimplePut(result, NULL, handler, origin, uri, + bodyData, bodySize, httpHeaders) == HttpStatus_200_Ok); } bool HttpToolbox::SimpleDelete(IHttpHandler& handler, @@ -221,7 +223,7 @@ const std::string& uri, const Arguments& httpHeaders) { - return IHttpHandler::SimpleDelete(handler, origin, uri, httpHeaders); + return (IHttpHandler::SimpleDelete(NULL, handler, origin, uri, httpHeaders) == HttpStatus_200_Ok); } #endif } diff -r b7fe3494a53c -r c8f444e8556d OrthancFramework/Sources/HttpServer/IHttpHandler.cpp --- a/OrthancFramework/Sources/HttpServer/IHttpHandler.cpp Wed Mar 17 15:48:31 2021 +0100 +++ b/OrthancFramework/Sources/HttpServer/IHttpHandler.cpp Tue Mar 30 16:34:02 2021 +0200 @@ -32,11 +32,12 @@ namespace Orthanc { - bool IHttpHandler::SimpleGet(std::string& result, - IHttpHandler& handler, - RequestOrigin origin, - const std::string& uri, - const HttpToolbox::Arguments& httpHeaders) + HttpStatus IHttpHandler::SimpleGet(std::string& answerBody, + HttpToolbox::Arguments* answerHeaders, + IHttpHandler& handler, + RequestOrigin origin, + const std::string& uri, + const HttpToolbox::Arguments& httpHeaders) { UriComponents curi; HttpToolbox::GetArguments getArguments; @@ -48,24 +49,31 @@ if (handler.Handle(http, origin, LOCALHOST, "", HttpMethod_Get, curi, httpHeaders, getArguments, NULL /* no body for GET */, 0)) { - stream.GetOutput(result); - return true; + stream.GetBody(answerBody); + + if (answerHeaders != NULL) + { + stream.GetHeaders(*answerHeaders, true /* convert key to lower case */); + } + + return stream.GetStatus(); } else { - return false; + return HttpStatus_404_NotFound; } } - static bool SimplePostOrPut(std::string& result, - IHttpHandler& handler, - RequestOrigin origin, - HttpMethod method, - const std::string& uri, - const void* bodyData, - size_t bodySize, - const HttpToolbox::Arguments& httpHeaders) + static HttpStatus SimplePostOrPut(std::string& answerBody, + HttpToolbox::Arguments* answerHeaders, + IHttpHandler& handler, + RequestOrigin origin, + HttpMethod method, + const std::string& uri, + const void* bodyData, + size_t bodySize, + const HttpToolbox::Arguments& httpHeaders) { HttpToolbox::GetArguments getArguments; // No GET argument for POST/PUT @@ -78,44 +86,53 @@ if (handler.Handle(http, origin, LOCALHOST, "", method, curi, httpHeaders, getArguments, bodyData, bodySize)) { - stream.GetOutput(result); - return true; + stream.GetBody(answerBody); + + if (answerHeaders != NULL) + { + stream.GetHeaders(*answerHeaders, true /* convert key to lower case */); + } + + return stream.GetStatus(); } else { - return false; + return HttpStatus_404_NotFound; } } - bool IHttpHandler::SimplePost(std::string& result, - IHttpHandler& handler, - RequestOrigin origin, - const std::string& uri, - const void* bodyData, - size_t bodySize, - const HttpToolbox::Arguments& httpHeaders) + HttpStatus IHttpHandler::SimplePost(std::string& answerBody, + HttpToolbox::Arguments* answerHeaders, + IHttpHandler& handler, + RequestOrigin origin, + const std::string& uri, + const void* bodyData, + size_t bodySize, + const HttpToolbox::Arguments& httpHeaders) { - return SimplePostOrPut(result, handler, origin, HttpMethod_Post, uri, bodyData, bodySize, httpHeaders); + return SimplePostOrPut(answerBody, answerHeaders, handler, origin, HttpMethod_Post, uri, bodyData, bodySize, httpHeaders); } - bool IHttpHandler::SimplePut(std::string& result, - IHttpHandler& handler, - RequestOrigin origin, - const std::string& uri, - const void* bodyData, - size_t bodySize, - const HttpToolbox::Arguments& httpHeaders) + HttpStatus IHttpHandler::SimplePut(std::string& answerBody, + HttpToolbox::Arguments* answerHeaders, + IHttpHandler& handler, + RequestOrigin origin, + const std::string& uri, + const void* bodyData, + size_t bodySize, + const HttpToolbox::Arguments& httpHeaders) { - return SimplePostOrPut(result, handler, origin, HttpMethod_Put, uri, bodyData, bodySize, httpHeaders); + return SimplePostOrPut(answerBody, answerHeaders, handler, origin, HttpMethod_Put, uri, bodyData, bodySize, httpHeaders); } - bool IHttpHandler::SimpleDelete(IHttpHandler& handler, - RequestOrigin origin, - const std::string& uri, - const HttpToolbox::Arguments& httpHeaders) + HttpStatus IHttpHandler::SimpleDelete(HttpToolbox::Arguments* answerHeaders, + IHttpHandler& handler, + RequestOrigin origin, + const std::string& uri, + const HttpToolbox::Arguments& httpHeaders) { UriComponents curi; Toolbox::SplitUriComponents(curi, uri); @@ -125,7 +142,19 @@ StringHttpOutput stream; HttpOutput http(stream, false /* no keep alive */); - return handler.Handle(http, origin, LOCALHOST, "", HttpMethod_Delete, curi, - httpHeaders, getArguments, NULL /* no body for DELETE */, 0); + if (handler.Handle(http, origin, LOCALHOST, "", HttpMethod_Delete, curi, + httpHeaders, getArguments, NULL /* no body for DELETE */, 0)) + { + if (answerHeaders != NULL) + { + stream.GetHeaders(*answerHeaders, true /* convert key to lower case */); + } + + return stream.GetStatus(); + } + else + { + return HttpStatus_404_NotFound; + } } } diff -r b7fe3494a53c -r c8f444e8556d OrthancFramework/Sources/HttpServer/IHttpHandler.h --- a/OrthancFramework/Sources/HttpServer/IHttpHandler.h Wed Mar 17 15:48:31 2021 +0100 +++ b/OrthancFramework/Sources/HttpServer/IHttpHandler.h Tue Mar 30 16:34:02 2021 +0200 @@ -83,31 +83,41 @@ const void* bodyData, size_t bodySize) = 0; - static bool SimpleGet(std::string& result, - IHttpHandler& handler, - RequestOrigin origin, - const std::string& uri, - const HttpToolbox::Arguments& httpHeaders); + + /** + * In the static functions below, "answerHeaders" can be set to + * NULL if the caller has no interest in HTTP headers of the + * answer (this avoids some computation). + **/ + static HttpStatus SimpleGet(std::string& answerBody /* out */, + HttpToolbox::Arguments* answerHeaders /* out */, + IHttpHandler& handler, + RequestOrigin origin, + const std::string& uri, + const HttpToolbox::Arguments& httpHeaders); - static bool SimplePost(std::string& result, - IHttpHandler& handler, - RequestOrigin origin, - const std::string& uri, - const void* bodyData, - size_t bodySize, - const HttpToolbox::Arguments& httpHeaders); + static HttpStatus SimplePost(std::string& answerBody /* out */, + HttpToolbox::Arguments* answerHeaders /* out */, + IHttpHandler& handler, + RequestOrigin origin, + const std::string& uri, + const void* bodyData, + size_t bodySize, + const HttpToolbox::Arguments& httpHeaders); - static bool SimplePut(std::string& result, - IHttpHandler& handler, - RequestOrigin origin, - const std::string& uri, - const void* bodyData, - size_t bodySize, - const HttpToolbox::Arguments& httpHeaders); + static HttpStatus SimplePut(std::string& answerBody /* out */, + HttpToolbox::Arguments* answerHeaders /* out */, + IHttpHandler& handler, + RequestOrigin origin, + const std::string& uri, + const void* bodyData, + size_t bodySize, + const HttpToolbox::Arguments& httpHeaders); - static bool SimpleDelete(IHttpHandler& handler, - RequestOrigin origin, - const std::string& uri, - const HttpToolbox::Arguments& httpHeaders); + static HttpStatus SimpleDelete(HttpToolbox::Arguments* answerHeaders /* out */, + IHttpHandler& handler, + RequestOrigin origin, + const std::string& uri, + const HttpToolbox::Arguments& httpHeaders); }; } diff -r b7fe3494a53c -r c8f444e8556d OrthancFramework/Sources/HttpServer/StringHttpOutput.cpp --- a/OrthancFramework/Sources/HttpServer/StringHttpOutput.cpp Wed Mar 17 15:48:31 2021 +0100 +++ b/OrthancFramework/Sources/HttpServer/StringHttpOutput.cpp Tue Mar 30 16:34:02 2021 +0200 @@ -24,43 +24,97 @@ #include "StringHttpOutput.h" #include "../OrthancException.h" +#include "../Toolbox.h" namespace Orthanc { - void StringHttpOutput::OnHttpStatusReceived(HttpStatus status) + StringHttpOutput::StringHttpOutput() : + status_(HttpStatus_404_NotFound), + validBody_(true), + validHeaders_(true) { - switch (status) + } + + + void StringHttpOutput::Send(bool isHeader, const void* buffer, size_t length) + { + if (isHeader) { - case HttpStatus_200_Ok: - found_ = true; - break; - - case HttpStatus_404_NotFound: - found_ = false; - break; - - default: - throw OrthancException(ErrorCode_BadRequest); + if (validHeaders_) + { + headers_.AddChunk(buffer, length); + } + else + { + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } + } + else + { + if (validBody_) + { + body_.AddChunk(buffer, length); + } + else + { + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } } } - void StringHttpOutput::Send(bool isHeader, const void* buffer, size_t length) + + void StringHttpOutput::GetBody(std::string& output) { - if (!isHeader) + if (!validBody_) { - buffer_.AddChunk(buffer, length); + throw OrthancException(ErrorCode_BadSequenceOfCalls); } - } - - void StringHttpOutput::GetOutput(std::string& output) - { - if (found_) + else if (status_ == HttpStatus_200_Ok) { - buffer_.Flatten(output); + body_.Flatten(output); + validBody_ = false; } else { throw OrthancException(ErrorCode_UnknownResource); } } + + + void StringHttpOutput::GetHeaders(std::map& target, + bool keyToLowerCase) + { + if (!validHeaders_) + { + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } + else + { + std::string s; + headers_.Flatten(s); + validHeaders_ = false; + + std::vector lines; + Orthanc::Toolbox::TokenizeString(lines, s, '\n'); + + target.clear(); + + for (size_t i = 1 /* skip the HTTP status line */; i < lines.size(); i++) + { + size_t colon = lines[i].find(':'); + if (colon != std::string::npos) + { + std::string key = lines[i].substr(0, colon); + + if (keyToLowerCase) + { + Toolbox::ToLowerCase(key); + } + + const std::string value = lines[i].substr(colon + 1); + target[Toolbox::StripSpaces(key)] = Toolbox::StripSpaces(value); + } + } + } + } } diff -r b7fe3494a53c -r c8f444e8556d OrthancFramework/Sources/HttpServer/StringHttpOutput.h --- a/OrthancFramework/Sources/HttpServer/StringHttpOutput.h Wed Mar 17 15:48:31 2021 +0100 +++ b/OrthancFramework/Sources/HttpServer/StringHttpOutput.h Tue Mar 30 16:34:02 2021 +0200 @@ -27,27 +27,42 @@ #include "../ChunkedBuffer.h" #include "../Compatibility.h" // For ORTHANC_OVERRIDE +#include + + namespace Orthanc { class StringHttpOutput : public IHttpOutputStream { private: - bool found_; - ChunkedBuffer buffer_; + HttpStatus status_; + ChunkedBuffer body_; + ChunkedBuffer headers_; + bool validBody_; + bool validHeaders_; public: - StringHttpOutput() : found_(false) + StringHttpOutput(); + + virtual void OnHttpStatusReceived(HttpStatus status) ORTHANC_OVERRIDE { + status_ = status; } - virtual void OnHttpStatusReceived(HttpStatus status) ORTHANC_OVERRIDE; - virtual void Send(bool isHeader, const void* buffer, size_t length) ORTHANC_OVERRIDE; virtual void DisableKeepAlive() ORTHANC_OVERRIDE { } - void GetOutput(std::string& output); + HttpStatus GetStatus() const + { + return status_; + } + + void GetBody(std::string& output); + + void GetHeaders(std::map& target, + bool keyToLowerCase); }; } diff -r b7fe3494a53c -r c8f444e8556d OrthancServer/Plugins/Engine/OrthancPlugins.cpp --- a/OrthancServer/Plugins/Engine/OrthancPlugins.cpp Wed Mar 17 15:48:31 2021 +0100 +++ b/OrthancServer/Plugins/Engine/OrthancPlugins.cpp Tue Mar 30 16:34:02 2021 +0200 @@ -153,6 +153,22 @@ } + static void CopyDictionary(OrthancPluginMemoryBuffer& target, + const std::map& dictionary) + { + Json::Value json = Json::objectValue; + + for (HttpClient::HttpHeaders::const_iterator + it = dictionary.begin(); it != dictionary.end(); ++it) + { + json[it->first] = it->second; + } + + std::string s = json.toStyledString(); + CopyToMemoryBuffer(target, s); + } + + namespace { class MemoryBufferRaii : public boost::noncopyable @@ -2674,7 +2690,7 @@ std::map httpHeaders; std::string result; - if (IHttpHandler::SimpleGet(result, *handler, RequestOrigin_Plugins, p.uri, httpHeaders)) + if (IHttpHandler::SimpleGet(result, NULL, *handler, RequestOrigin_Plugins, p.uri, httpHeaders) == HttpStatus_200_Ok) { CopyToMemoryBuffer(*p.target, result); } @@ -2710,7 +2726,7 @@ } std::string result; - if (IHttpHandler::SimpleGet(result, *handler, RequestOrigin_Plugins, p.uri, headers)) + if (IHttpHandler::SimpleGet(result, NULL, *handler, RequestOrigin_Plugins, p.uri, headers) == HttpStatus_200_Ok) { CopyToMemoryBuffer(*p.target, result); } @@ -2742,8 +2758,10 @@ std::string result; if (isPost ? - IHttpHandler::SimplePost(result, *handler, RequestOrigin_Plugins, p.uri, p.body, p.bodySize, httpHeaders) : - IHttpHandler::SimplePut (result, *handler, RequestOrigin_Plugins, p.uri, p.body, p.bodySize, httpHeaders)) + IHttpHandler::SimplePost(result, NULL, *handler, RequestOrigin_Plugins, p.uri, + p.body, p.bodySize, httpHeaders) == HttpStatus_200_Ok : + IHttpHandler::SimplePut(result, NULL, *handler, RequestOrigin_Plugins, p.uri, + p.body, p.bodySize, httpHeaders) == HttpStatus_200_Ok) { CopyToMemoryBuffer(*p.target, result); } @@ -2770,7 +2788,7 @@ std::map httpHeaders; - if (!IHttpHandler::SimpleDelete(*handler, RequestOrigin_Plugins, uri, httpHeaders)) + if (IHttpHandler::SimpleDelete(NULL, *handler, RequestOrigin_Plugins, uri, httpHeaders) != HttpStatus_200_Ok) { throw OrthancException(ErrorCode_UnknownResource); } @@ -3329,11 +3347,6 @@ OrthancPluginMemoryBuffer* answerHeaders, HttpClient& client) { - if (answerBody == NULL) - { - throw OrthancException(ErrorCode_NullPointer); - } - std::string body; HttpClient::HttpHeaders headers; @@ -3350,22 +3363,27 @@ // Copy the HTTP headers of the answer, if the plugin requested them if (answerHeaders != NULL) { - Json::Value json = Json::objectValue; - - for (HttpClient::HttpHeaders::const_iterator - it = headers.begin(); it != headers.end(); ++it) - { - json[it->first] = it->second; - } - - std::string s = json.toStyledString(); - CopyToMemoryBuffer(*answerHeaders, s); + CopyDictionary(*answerHeaders, headers); } // Copy the body of the answer if it makes sense if (client.GetMethod() != HttpMethod_Delete) { - CopyToMemoryBuffer(*answerBody, body); + try + { + if (answerBody != NULL) + { + CopyToMemoryBuffer(*answerBody, body); + } + } + catch (OrthancException&) + { + if (answerHeaders != NULL) + { + free(answerHeaders->data); + } + throw; + } } } @@ -3481,6 +3499,112 @@ } + void OrthancPlugins::CallRestApi(const void* parameters) + { + const _OrthancPluginCallRestApi& p = *reinterpret_cast(parameters); + + if (p.httpStatus == NULL) + { + throw OrthancException(ErrorCode_NullPointer); + } + + const char* methodString; + switch (p.method) + { + case OrthancPluginHttpMethod_Get: + methodString = "GET"; + break; + + case OrthancPluginHttpMethod_Post: + methodString = "POST"; + break; + + case OrthancPluginHttpMethod_Put: + methodString = "PUT"; + break; + + case OrthancPluginHttpMethod_Delete: + methodString = "DELETE"; + break; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + + CLOG(INFO, PLUGINS) << "Plugin making REST " << methodString << " call to URI " << p.uri + << (p.afterPlugins ? " (after plugins)" : " (built-in API)"); + + HttpToolbox::Arguments headers; + + for (uint32_t i = 0; i < p.headersCount; i++) + { + std::string name(p.headersKeys[i]); + std::transform(name.begin(), name.end(), name.begin(), ::tolower); + headers[name] = p.headersValues[i]; + } + + IHttpHandler* handler; + + { + PImpl::ServerContextLock lock(*pimpl_); + handler = &lock.GetContext().GetHttpHandler().RestrictToOrthancRestApi(!p.afterPlugins); + } + + std::string answerBody; + std::map answerHeaders; + HttpStatus status; + + switch (p.method) + { + case OrthancPluginHttpMethod_Get: + status = IHttpHandler::SimpleGet( + answerBody, &answerHeaders, *handler, RequestOrigin_Plugins, p.uri, headers); + break; + + case OrthancPluginHttpMethod_Post: + status = IHttpHandler::SimplePost( + answerBody, &answerHeaders, *handler, RequestOrigin_Plugins, p.uri, p.body, p.bodySize, headers); + break; + + case OrthancPluginHttpMethod_Put: + status = IHttpHandler::SimplePut( + answerBody, &answerHeaders, *handler, RequestOrigin_Plugins, p.uri, p.body, p.bodySize, headers); + break; + + case OrthancPluginHttpMethod_Delete: + status = IHttpHandler::SimpleDelete( + &answerHeaders, *handler, RequestOrigin_Plugins, p.uri, headers); + break; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + + *p.httpStatus = static_cast(status); + + if (p.answerHeaders != NULL) + { + CopyDictionary(*p.answerHeaders, answerHeaders); + } + + try + { + if (p.answerBody != NULL) + { + CopyToMemoryBuffer(*p.answerBody, answerBody); + } + } + catch (OrthancException&) + { + if (p.answerHeaders != NULL) + { + free(p.answerHeaders->data); + } + throw; + } + } + + void OrthancPlugins::CallPeerApi(const void* parameters) { const _OrthancPluginCallPeerApi& p = *reinterpret_cast(parameters); @@ -3545,22 +3669,27 @@ // Copy the HTTP headers of the answer, if the plugin requested them if (p.answerHeaders != NULL) { - Json::Value json = Json::objectValue; - - for (HttpClient::HttpHeaders::const_iterator - it = headers.begin(); it != headers.end(); ++it) - { - json[it->first] = it->second; - } - - std::string s = json.toStyledString(); - CopyToMemoryBuffer(*p.answerHeaders, s); + CopyDictionary(*p.answerHeaders, headers); } // Copy the body of the answer if it makes sense if (p.method != OrthancPluginHttpMethod_Delete) { - CopyToMemoryBuffer(*p.answerBody, body); + try + { + if (p.answerBody != NULL) + { + CopyToMemoryBuffer(*p.answerBody, body); + } + } + catch (OrthancException&) + { + if (p.answerHeaders != NULL) + { + free(p.answerHeaders->data); + } + throw; + } } } @@ -4218,6 +4347,10 @@ ChunkedHttpClient(parameters); return true; + case _OrthancPluginService_CallRestApi: + CallRestApi(parameters); + return true; + case _OrthancPluginService_ConvertPixelFormat: ConvertPixelFormat(parameters); return true; diff -r b7fe3494a53c -r c8f444e8556d OrthancServer/Plugins/Engine/OrthancPlugins.h --- a/OrthancServer/Plugins/Engine/OrthancPlugins.h Wed Mar 17 15:48:31 2021 +0100 +++ b/OrthancServer/Plugins/Engine/OrthancPlugins.h Tue Mar 30 16:34:02 2021 +0200 @@ -196,6 +196,8 @@ void ChunkedHttpClient(const void* parameters); + void CallRestApi(const void* parameters); + void CallPeerApi(const void* parameters); void GetFontInfo(const void* parameters); diff -r b7fe3494a53c -r c8f444e8556d OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h --- a/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h Wed Mar 17 15:48:31 2021 +0100 +++ b/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h Tue Mar 30 16:34:02 2021 +0200 @@ -117,7 +117,7 @@ #define ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER 1 #define ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER 9 -#define ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER 0 +#define ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER 2 #if !defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE) @@ -493,6 +493,7 @@ _OrthancPluginService_RestApiPutAfterPlugins = 3013, _OrthancPluginService_ReconstructMainDicomTags = 3014, _OrthancPluginService_RestApiGet2 = 3015, + _OrthancPluginService_CallRestApi = 3016, /* New in Orthanc 1.9.2 */ /* Access to DICOM instances */ _OrthancPluginService_GetInstanceRemoteAet = 4000, @@ -5756,6 +5757,7 @@ * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). * @param answerBody The target memory buffer (out argument). * It must be freed with OrthancPluginFreeMemoryBuffer(). + * The value of this argument is ignored if the HTTP method is DELETE. * @param answerHeaders The target memory buffer for the HTTP headers in the answers (out argument). * The answer headers are formatted as a JSON object (associative array). * The buffer must be freed with OrthancPluginFreeMemoryBuffer(). @@ -6560,6 +6562,7 @@ * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). * @param answerBody The target memory buffer (out argument). * It must be freed with OrthancPluginFreeMemoryBuffer(). + * The value of this argument is ignored if the HTTP method is DELETE. * @param answerHeaders The target memory buffer for the HTTP headers in the answers (out argument). * The answer headers are formatted as a JSON object (associative array). * The buffer must be freed with OrthancPluginFreeMemoryBuffer(). @@ -8483,6 +8486,89 @@ return context->InvokeService(context, _OrthancPluginService_CreateDicom2, ¶ms); } + + + + + + typedef struct + { + OrthancPluginMemoryBuffer* answerBody; + OrthancPluginMemoryBuffer* answerHeaders; + uint16_t* httpStatus; + OrthancPluginHttpMethod method; + const char* uri; + uint32_t headersCount; + const char* const* headersKeys; + const char* const* headersValues; + const void* body; + uint32_t bodySize; + uint8_t afterPlugins; + } _OrthancPluginCallRestApi; + + /** + * @brief Call the REST API of Orthanc with full flexibility. + * + * Make a call to the given URI in the REST API of Orthanc. The + * result to the query is stored into a newly allocated memory + * buffer. This function is always granted full access to the REST + * API (no credentials, nor security token is needed). + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param answerBody The target memory buffer (out argument). + * It must be freed with OrthancPluginFreeMemoryBuffer(). + * The value of this argument is ignored if the HTTP method is DELETE. + * @param answerHeaders The target memory buffer for the HTTP headers in the answer (out argument). + * The answer headers are formatted as a JSON object (associative array). + * The buffer must be freed with OrthancPluginFreeMemoryBuffer(). + * This argument can be set to NULL if the plugin has no interest in the answer HTTP headers. + * @param httpStatus The HTTP status after the execution of the request (out argument). + * @param method HTTP method to be used. + * @param uri The URI of interest. + * @param headersCount The number of HTTP headers. + * @param headersKeys Array containing the keys of the HTTP headers (can be NULL if no header). + * @param headersValues Array containing the values of the HTTP headers (can be NULL if no header). + * @param body The HTTP body for a POST or PUT request. + * @param bodySize The size of the body. + * @param afterPlugins If 0, the built-in API of Orthanc is used. + * If 1, the API is tainted by the plugins. + * @return 0 if success, or the error code if failure. + * @see OrthancPluginRestApiGet2, OrthancPluginRestApiPost, OrthancPluginRestApiPut, OrthancPluginRestApiDelete + * @ingroup Orthanc + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginCallRestApi( + OrthancPluginContext* context, + OrthancPluginMemoryBuffer* answerBody, + OrthancPluginMemoryBuffer* answerHeaders, + uint16_t* httpStatus, + OrthancPluginHttpMethod method, + const char* uri, + uint32_t headersCount, + const char* const* headersKeys, + const char* const* headersValues, + const void* body, + uint32_t bodySize, + uint8_t afterPlugins) + { + _OrthancPluginCallRestApi params; + memset(¶ms, 0, sizeof(params)); + + params.answerBody = answerBody; + params.answerHeaders = answerHeaders; + params.httpStatus = httpStatus; + params.method = method; + params.uri = uri; + params.headersCount = headersCount; + params.headersKeys = headersKeys; + params.headersValues = headersValues; + params.body = body; + params.bodySize = bodySize; + params.afterPlugins = afterPlugins; + + return context->InvokeService(context, _OrthancPluginService_CallRestApi, ¶ms); + } + + #ifdef __cplusplus } #endif diff -r b7fe3494a53c -r c8f444e8556d OrthancServer/Sources/LuaScripting.cpp --- a/OrthancServer/Sources/LuaScripting.cpp Wed Mar 17 15:48:31 2021 +0100 +++ b/OrthancServer/Sources/LuaScripting.cpp Tue Mar 30 16:34:02 2021 +0200 @@ -405,8 +405,8 @@ try { std::string result; - if (IHttpHandler::SimpleGet(result, serverContext->GetHttpHandler().RestrictToOrthancRestApi(builtin), - RequestOrigin_Lua, uri, headers)) + if (IHttpHandler::SimpleGet(result, NULL, serverContext->GetHttpHandler().RestrictToOrthancRestApi(builtin), + RequestOrigin_Lua, uri, headers) == HttpStatus_200_Ok) { lua_pushlstring(state, result.c_str(), result.size()); return 1; @@ -458,10 +458,12 @@ { std::string result; if (isPost ? - IHttpHandler::SimplePost(result, serverContext->GetHttpHandler().RestrictToOrthancRestApi(builtin), - RequestOrigin_Lua, uri, bodyData, bodySize, headers) : - IHttpHandler::SimplePut(result, serverContext->GetHttpHandler().RestrictToOrthancRestApi(builtin), - RequestOrigin_Lua, uri, bodyData, bodySize, headers)) + IHttpHandler::SimplePost(result, NULL, + serverContext->GetHttpHandler().RestrictToOrthancRestApi(builtin), + RequestOrigin_Lua, uri, bodyData, bodySize, headers) == HttpStatus_200_Ok : + IHttpHandler::SimplePut(result, NULL, + serverContext->GetHttpHandler().RestrictToOrthancRestApi(builtin), + RequestOrigin_Lua, uri, bodyData, bodySize, headers) == HttpStatus_200_Ok) { lua_pushlstring(state, result.c_str(), result.size()); return 1; @@ -522,8 +524,8 @@ try { - if (IHttpHandler::SimpleDelete(serverContext->GetHttpHandler().RestrictToOrthancRestApi(builtin), - RequestOrigin_Lua, uri, headers)) + if (IHttpHandler::SimpleDelete(NULL, serverContext->GetHttpHandler().RestrictToOrthancRestApi(builtin), + RequestOrigin_Lua, uri, headers) == HttpStatus_200_Ok) { lua_pushboolean(state, 1); return 1;