# HG changeset patch # User Sebastien Jodogne # Date 1410252203 -7200 # Node ID f739d3f6cfcf32e7849b44a189897a199dbd148f # Parent ac6bd50a8c83b442ddfbc0f2a08abb32d749d77f rename diff -r ac6bd50a8c83 -r f739d3f6cfcf CMakeLists.txt --- a/CMakeLists.txt Mon Sep 08 17:34:33 2014 +0200 +++ b/CMakeLists.txt Tue Sep 09 10:43:23 2014 +0200 @@ -130,7 +130,7 @@ Plugins/Engine/SharedLibrary.cpp Plugins/Engine/PluginsManager.cpp - Plugins/Engine/PluginsHttpHandler.cpp + Plugins/Engine/OrthancPlugins.cpp ) diff -r ac6bd50a8c83 -r f739d3f6cfcf OrthancServer/main.cpp --- a/OrthancServer/main.cpp Mon Sep 08 17:34:33 2014 +0200 +++ b/OrthancServer/main.cpp Tue Sep 09 10:43:23 2014 +0200 @@ -51,7 +51,7 @@ #include "OrthancMoveRequestHandler.h" #include "ServerToolbox.h" #include "../Plugins/Engine/PluginsManager.h" -#include "../Plugins/Engine/PluginsHttpHandler.h" +#include "../Plugins/Engine/OrthancPlugins.h" using namespace Orthanc; @@ -451,18 +451,18 @@ FilesystemHttpHandler staticResources("/app", ORTHANC_PATH "/OrthancExplorer"); #endif - PluginsHttpHandler httpPlugins(context); - httpPlugins.SetOrthancRestApi(restApi); + OrthancPlugins orthancPlugins(context); + orthancPlugins.SetOrthancRestApi(restApi); PluginsManager pluginsManager; - pluginsManager.RegisterServiceProvider(httpPlugins); + pluginsManager.RegisterServiceProvider(orthancPlugins); LoadPlugins(pluginsManager); - httpServer.RegisterHandler(httpPlugins); + httpServer.RegisterHandler(orthancPlugins); httpServer.RegisterHandler(staticResources); httpServer.RegisterHandler(restApi); - httpPlugins.SetOrthancRestApi(restApi); - context.SetPluginsHttpHandler(httpPlugins); + orthancPlugins.SetOrthancRestApi(restApi); + context.SetOrthancPlugins(orthancPlugins); // GO !!! Start the requested servers if (Configuration::GetGlobalBoolParameter("HttpServerEnabled", true)) diff -r ac6bd50a8c83 -r f739d3f6cfcf Plugins/Engine/OrthancPlugins.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Engine/OrthancPlugins.cpp Tue Sep 09 10:43:23 2014 +0200 @@ -0,0 +1,819 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2014 Medical Physics Department, CHU of Liege, + * Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + + +#include "PluginsHttpHandler.h" + +#include "../../Core/ChunkedBuffer.h" +#include "../../Core/OrthancException.h" +#include "../../Core/Toolbox.h" +#include "../../Core/HttpServer/HttpOutput.h" +#include "../../Core/ImageFormats/PngWriter.h" +#include "../../OrthancServer/ServerToolbox.h" + +#include +#include + +namespace Orthanc +{ + namespace + { + // Anonymous namespace to avoid clashes between compilation modules + class StringHttpOutput : public IHttpOutputStream + { + private: + ChunkedBuffer buffer_; + + public: + void GetOutput(std::string& output) + { + buffer_.Flatten(output); + } + + virtual void OnHttpStatusReceived(HttpStatus status) + { + if (status != HttpStatus_200_Ok) + { + throw OrthancException(ErrorCode_BadRequest); + } + } + + virtual void Send(bool isHeader, const void* buffer, size_t length) + { + if (!isHeader) + { + buffer_.AddChunk(reinterpret_cast(buffer), length); + } + } + }; + } + + + + struct PluginsHttpHandler::PImpl + { + typedef std::pair RestCallback; + typedef std::list RestCallbacks; + typedef std::list OnStoredCallbacks; + + ServerContext& context_; + RestCallbacks restCallbacks_; + OrthancRestApi* restApi_; + OnStoredCallbacks onStoredCallbacks_; + + PImpl(ServerContext& context) : context_(context), restApi_(NULL) + { + } + }; + + + static char* CopyString(const std::string& str) + { + char *result = reinterpret_cast(malloc(str.size() + 1)); + if (result == NULL) + { + throw OrthancException(ErrorCode_NotEnoughMemory); + } + + if (str.size() == 0) + { + result[0] = '\0'; + } + else + { + memcpy(result, &str[0], str.size() + 1); + } + + return result; + } + + + PluginsHttpHandler::PluginsHttpHandler(ServerContext& context) + { + pimpl_.reset(new PImpl(context)); + } + + + PluginsHttpHandler::~PluginsHttpHandler() + { + for (PImpl::RestCallbacks::iterator it = pimpl_->restCallbacks_.begin(); + it != pimpl_->restCallbacks_.end(); ++it) + { + // Delete the regular expression associated with this callback + delete it->first; + } + } + + + static void ArgumentsToPlugin(std::vector& keys, + std::vector& values, + const HttpHandler::Arguments& arguments) + { + keys.resize(arguments.size()); + values.resize(arguments.size()); + + size_t pos = 0; + for (HttpHandler::Arguments::const_iterator + it = arguments.begin(); it != arguments.end(); ++it) + { + keys[pos] = it->first.c_str(); + values[pos] = it->second.c_str(); + pos++; + } + } + + + bool PluginsHttpHandler::Handle(HttpOutput& output, + HttpMethod method, + const UriComponents& uri, + const Arguments& headers, + const Arguments& getArguments, + const std::string& postData) + { + std::string flatUri = Toolbox::FlattenUri(uri); + OrthancPluginRestCallback callback = NULL; + + std::vector groups; + std::vector cgroups; + + // Loop over the callbacks registered by the plugins + bool found = false; + for (PImpl::RestCallbacks::const_iterator it = pimpl_->restCallbacks_.begin(); + it != pimpl_->restCallbacks_.end() && !found; ++it) + { + // Check whether the regular expression associated to this + // callback matches the URI + boost::cmatch what; + if (boost::regex_match(flatUri.c_str(), what, *(it->first))) + { + callback = it->second; + + // Extract the value of the free parameters of the regular expression + 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; + + std::vector getKeys, getValues, headersKeys, headersValues; + + OrthancPluginHttpRequest request; + memset(&request, 0, sizeof(OrthancPluginHttpRequest)); + + ArgumentsToPlugin(headersKeys, headersValues, headers); + + switch (method) + { + case HttpMethod_Get: + request.method = OrthancPluginHttpMethod_Get; + ArgumentsToPlugin(getKeys, getValues, getArguments); + break; + + case HttpMethod_Post: + request.method = OrthancPluginHttpMethod_Post; + break; + + case HttpMethod_Delete: + request.method = OrthancPluginHttpMethod_Delete; + break; + + case HttpMethod_Put: + request.method = OrthancPluginHttpMethod_Put; + break; + + default: + throw OrthancException(ErrorCode_InternalError); + } + + + request.groups = (cgroups.size() ? &cgroups[0] : NULL); + request.groupsCount = cgroups.size(); + request.getCount = getArguments.size(); + request.body = (postData.size() ? &postData[0] : NULL); + request.bodySize = postData.size(); + request.headersCount = headers.size(); + + if (getArguments.size() > 0) + { + request.getKeys = &getKeys[0]; + request.getValues = &getValues[0]; + } + + if (headers.size() > 0) + { + request.headersKeys = &headersKeys[0]; + request.headersValues = &headersValues[0]; + } + + assert(callback != NULL); + int32_t error = callback(reinterpret_cast(&output), + flatUri.c_str(), + &request); + + if (error < 0) + { + LOG(ERROR) << "Plugin callback failed with error code " << error; + return false; + } + else + { + if (error > 0) + { + LOG(WARNING) << "Plugin callback finished with warning code " << error; + } + + return true; + } + } + + + void PluginsHttpHandler::SignalStoredInstance(DicomInstanceToStore& instance, + const std::string& instanceId) + { + for (PImpl::OnStoredCallbacks::const_iterator + callback = pimpl_->onStoredCallbacks_.begin(); + callback != pimpl_->onStoredCallbacks_.end(); ++callback) + { + (*callback) (reinterpret_cast(&instance), + instanceId.c_str()); + } + } + + + + static void CopyToMemoryBuffer(OrthancPluginMemoryBuffer& target, + const void* data, + size_t size) + { + target.size = size; + + if (size == 0) + { + target.data = NULL; + } + else + { + target.data = malloc(size); + if (target.data != NULL) + { + memcpy(target.data, data, size); + } + else + { + throw OrthancException(ErrorCode_NotEnoughMemory); + } + } + } + + + static void CopyToMemoryBuffer(OrthancPluginMemoryBuffer& target, + const std::string& str) + { + if (str.size() == 0) + { + target.size = 0; + target.data = NULL; + } + else + { + CopyToMemoryBuffer(target, str.c_str(), str.size()); + } + } + + + void PluginsHttpHandler::RegisterRestCallback(const void* parameters) + { + const _OrthancPluginRestCallback& p = + *reinterpret_cast(parameters); + + LOG(INFO) << "Plugin has registered a REST callback on: " << p.pathRegularExpression; + pimpl_->restCallbacks_.push_back(std::make_pair(new boost::regex(p.pathRegularExpression), p.callback)); + } + + + + void PluginsHttpHandler::RegisterOnStoredInstanceCallback(const void* parameters) + { + const _OrthancPluginOnStoredInstanceCallback& p = + *reinterpret_cast(parameters); + + LOG(INFO) << "Plugin has registered an OnStoredInstance callback"; + pimpl_->onStoredCallbacks_.push_back(p.callback); + } + + + + void PluginsHttpHandler::AnswerBuffer(const void* parameters) + { + const _OrthancPluginAnswerBuffer& p = + *reinterpret_cast(parameters); + + HttpOutput* translatedOutput = reinterpret_cast(p.output); + translatedOutput->SetContentType(p.mimeType); + translatedOutput->SendBody(p.answer, p.answerSize); + } + + + void PluginsHttpHandler::Redirect(const void* parameters) + { + const _OrthancPluginOutputPlusArgument& p = + *reinterpret_cast(parameters); + + HttpOutput* translatedOutput = reinterpret_cast(p.output); + translatedOutput->Redirect(p.argument); + } + + + void PluginsHttpHandler::SendHttpStatusCode(const void* parameters) + { + const _OrthancPluginSendHttpStatusCode& p = + *reinterpret_cast(parameters); + + HttpOutput* translatedOutput = reinterpret_cast(p.output); + translatedOutput->SendStatus(static_cast(p.status)); + } + + + void PluginsHttpHandler::SendUnauthorized(const void* parameters) + { + const _OrthancPluginOutputPlusArgument& p = + *reinterpret_cast(parameters); + + HttpOutput* translatedOutput = reinterpret_cast(p.output); + translatedOutput->SendUnauthorized(p.argument); + } + + + void PluginsHttpHandler::SendMethodNotAllowed(const void* parameters) + { + const _OrthancPluginOutputPlusArgument& p = + *reinterpret_cast(parameters); + + HttpOutput* translatedOutput = reinterpret_cast(p.output); + translatedOutput->SendMethodNotAllowed(p.argument); + } + + + void PluginsHttpHandler::SetCookie(const void* parameters) + { + const _OrthancPluginSetCookie& p = + *reinterpret_cast(parameters); + + HttpOutput* translatedOutput = reinterpret_cast(p.output); + translatedOutput->SetCookie(p.cookie, p.value); + } + + + void PluginsHttpHandler::CompressAndAnswerPngImage(const void* parameters) + { + const _OrthancPluginCompressAndAnswerPngImage& 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->SetContentType("image/png"); + translatedOutput->SendBody(png); + } + + + void PluginsHttpHandler::GetDicomForInstance(const void* parameters) + { + const _OrthancPluginGetDicomForInstance& p = + *reinterpret_cast(parameters); + + std::string dicom; + pimpl_->context_.ReadFile(dicom, p.instanceId, FileContentType_Dicom); + CopyToMemoryBuffer(*p.target, dicom); + } + + + void PluginsHttpHandler::RestApiGet(const void* parameters) + { + const _OrthancPluginRestApiGet& p = + *reinterpret_cast(parameters); + + HttpHandler::Arguments headers; // No HTTP header + std::string body; // No body for a GET request + + UriComponents uri; + HttpHandler::Arguments getArguments; + HttpHandler::ParseGetQuery(uri, getArguments, p.uri); + + StringHttpOutput stream; + HttpOutput http(stream, false /* no keep alive */); + + LOG(INFO) << "Plugin making REST GET call on URI " << p.uri; + + if (pimpl_->restApi_ != NULL && + pimpl_->restApi_->Handle(http, HttpMethod_Get, uri, headers, getArguments, body)) + { + std::string result; + stream.GetOutput(result); + CopyToMemoryBuffer(*p.target, result); + } + else + { + throw OrthancException(ErrorCode_BadRequest); + } + } + + + void PluginsHttpHandler::RestApiPostPut(bool isPost, const void* parameters) + { + const _OrthancPluginRestApiPostPut& p = + *reinterpret_cast(parameters); + + HttpHandler::Arguments headers; // No HTTP header + HttpHandler::Arguments getArguments; // No GET argument for POST/PUT + + UriComponents uri; + Toolbox::SplitUriComponents(uri, p.uri); + + // TODO Avoid unecessary memcpy + std::string body(p.body, p.bodySize); + + StringHttpOutput stream; + HttpOutput http(stream, false /* no keep alive */); + + HttpMethod method = (isPost ? HttpMethod_Post : HttpMethod_Put); + LOG(INFO) << "Plugin making REST " << EnumerationToString(method) << " call on URI " << p.uri; + + if (pimpl_->restApi_ != NULL && + pimpl_->restApi_->Handle(http, method, uri, headers, getArguments, body)) + { + std::string result; + stream.GetOutput(result); + CopyToMemoryBuffer(*p.target, result); + } + else + { + throw OrthancException(ErrorCode_BadRequest); + } + } + + + void PluginsHttpHandler::RestApiDelete(const void* parameters) + { + // The "parameters" point to the URI + UriComponents uri; + Toolbox::SplitUriComponents(uri, reinterpret_cast(parameters)); + + HttpHandler::Arguments headers; // No HTTP header + HttpHandler::Arguments getArguments; // No GET argument for POST/PUT + std::string body; // No body for DELETE + + StringHttpOutput stream; + HttpOutput http(stream, false /* no keep alive */); + + LOG(INFO) << "Plugin making REST DELETE call on URI " + << reinterpret_cast(parameters); + + if (pimpl_->restApi_ == NULL || + !pimpl_->restApi_->Handle(http, HttpMethod_Delete, uri, headers, getArguments, body)) + { + throw OrthancException(ErrorCode_BadRequest); + } + } + + + void PluginsHttpHandler::LookupResource(_OrthancPluginService service, + const void* parameters) + { + const _OrthancPluginLookupResource& p = + *reinterpret_cast(parameters); + + /** + * The enumeration below only uses the tags that are indexed in + * the Orthanc database. It reflects the + * "CandidateResources::ApplyFilter()" method of the + * "OrthancFindRequestHandler" class. + **/ + + DicomTag tag(0, 0); + ResourceType level; + switch (service) + { + case _OrthancPluginService_LookupPatient: + tag = DICOM_TAG_PATIENT_ID; + level = ResourceType_Patient; + break; + + case _OrthancPluginService_LookupStudy: + tag = DICOM_TAG_STUDY_INSTANCE_UID; + level = ResourceType_Study; + break; + + case _OrthancPluginService_LookupStudyWithAccessionNumber: + tag = DICOM_TAG_ACCESSION_NUMBER; + level = ResourceType_Study; + break; + + case _OrthancPluginService_LookupSeries: + tag = DICOM_TAG_SERIES_INSTANCE_UID; + level = ResourceType_Series; + break; + + case _OrthancPluginService_LookupInstance: + tag = DICOM_TAG_SOP_INSTANCE_UID; + level = ResourceType_Instance; + break; + + default: + throw OrthancException(ErrorCode_InternalError); + } + + std::list result; + pimpl_->context_.GetIndex().LookupTagValue(result, tag, p.identifier, level); + + if (result.size() == 1) + { + *p.result = CopyString(result.front()); + } + else + { + throw OrthancException(ErrorCode_UnknownResource); + } + } + + + static void AccessInstanceMetadataInternal(bool checkExistence, + const _OrthancPluginAccessDicomInstance& params, + const DicomInstanceToStore& instance) + { + MetadataType metadata; + + try + { + metadata = StringToMetadata(params.key); + } + catch (OrthancException&) + { + // Unknown metadata + if (checkExistence) + { + *params.resultInt64 = -1; + } + else + { + *params.resultString = NULL; + } + + return; + } + + ServerIndex::MetadataMap::const_iterator it = + instance.GetMetadata().find(std::make_pair(ResourceType_Instance, metadata)); + + if (checkExistence) + { + if (it != instance.GetMetadata().end()) + { + *params.resultInt64 = 1; + } + else + { + *params.resultInt64 = 0; + } + } + else + { + if (it != instance.GetMetadata().end()) + { + *params.resultString = it->second.c_str(); + } + else + { + // Error: Missing metadata + *params.resultString = NULL; + } + } + } + + + static void AccessDicomInstance(_OrthancPluginService service, + const void* parameters) + { + const _OrthancPluginAccessDicomInstance& p = + *reinterpret_cast(parameters); + + DicomInstanceToStore& instance = + *reinterpret_cast(p.instance); + + switch (service) + { + case _OrthancPluginService_GetInstanceRemoteAet: + *p.resultString = instance.GetRemoteAet().c_str(); + return; + + case _OrthancPluginService_GetInstanceSize: + *p.resultInt64 = instance.GetBufferSize(); + return; + + case _OrthancPluginService_GetInstanceData: + *p.resultString = instance.GetBufferData(); + return; + + case _OrthancPluginService_HasInstanceMetadata: + AccessInstanceMetadataInternal(true, p, instance); + return; + + case _OrthancPluginService_GetInstanceMetadata: + AccessInstanceMetadataInternal(false, p, instance); + return; + + case _OrthancPluginService_GetInstanceJson: + case _OrthancPluginService_GetInstanceSimplifiedJson: + { + Json::StyledWriter writer; + std::string s; + + if (service == _OrthancPluginService_GetInstanceJson) + { + s = writer.write(instance.GetJson()); + } + else + { + Json::Value simplified; + SimplifyTags(simplified, instance.GetJson()); + s = writer.write(simplified); + } + + *p.resultStringToFree = CopyString(s); + return; + } + + default: + throw OrthancException(ErrorCode_InternalError); + } + } + + + bool PluginsHttpHandler::InvokeService(_OrthancPluginService service, + const void* parameters) + { + switch (service) + { + case _OrthancPluginService_RegisterRestCallback: + RegisterRestCallback(parameters); + return true; + + case _OrthancPluginService_RegisterOnStoredInstanceCallback: + RegisterOnStoredInstanceCallback(parameters); + return true; + + case _OrthancPluginService_AnswerBuffer: + AnswerBuffer(parameters); + return true; + + case _OrthancPluginService_CompressAndAnswerPngImage: + CompressAndAnswerPngImage(parameters); + return true; + + case _OrthancPluginService_GetDicomForInstance: + GetDicomForInstance(parameters); + return true; + + case _OrthancPluginService_RestApiGet: + RestApiGet(parameters); + return true; + + case _OrthancPluginService_RestApiPost: + RestApiPostPut(true, parameters); + return true; + + case _OrthancPluginService_RestApiDelete: + RestApiDelete(parameters); + return true; + + case _OrthancPluginService_RestApiPut: + RestApiPostPut(false, parameters); + return true; + + case _OrthancPluginService_Redirect: + Redirect(parameters); + return true; + + case _OrthancPluginService_SendUnauthorized: + SendUnauthorized(parameters); + return true; + + case _OrthancPluginService_SendMethodNotAllowed: + SendMethodNotAllowed(parameters); + return true; + + case _OrthancPluginService_SendHttpStatusCode: + SendHttpStatusCode(parameters); + return true; + + case _OrthancPluginService_SetCookie: + SetCookie(parameters); + return true; + + case _OrthancPluginService_LookupPatient: + case _OrthancPluginService_LookupStudy: + case _OrthancPluginService_LookupStudyWithAccessionNumber: + case _OrthancPluginService_LookupSeries: + case _OrthancPluginService_LookupInstance: + LookupResource(service, parameters); + return true; + + case _OrthancPluginService_GetInstanceRemoteAet: + case _OrthancPluginService_GetInstanceSize: + case _OrthancPluginService_GetInstanceData: + case _OrthancPluginService_GetInstanceJson: + case _OrthancPluginService_GetInstanceSimplifiedJson: + case _OrthancPluginService_HasInstanceMetadata: + case _OrthancPluginService_GetInstanceMetadata: + AccessDicomInstance(service, parameters); + return true; + + default: + return false; + } + } + + + void PluginsHttpHandler::SetOrthancRestApi(OrthancRestApi& restApi) + { + pimpl_->restApi_ = &restApi; + } + +} diff -r ac6bd50a8c83 -r f739d3f6cfcf Plugins/Engine/OrthancPlugins.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Engine/OrthancPlugins.h Tue Sep 09 10:43:23 2014 +0200 @@ -0,0 +1,102 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2014 Medical Physics Department, CHU of Liege, + * Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include "PluginsManager.h" +#include "../../Core/HttpServer/HttpHandler.h" +#include "../../OrthancServer/ServerContext.h" +#include "../../OrthancServer/OrthancRestApi/OrthancRestApi.h" +#include "../OrthancCPlugin/OrthancCPlugin.h" + +#include +#include + +namespace Orthanc +{ + class PluginsHttpHandler : public HttpHandler, public IPluginServiceProvider + { + private: + struct PImpl; + + boost::shared_ptr pimpl_; + + void RegisterRestCallback(const void* parameters); + + void RegisterOnStoredInstanceCallback(const void* parameters); + + void AnswerBuffer(const void* parameters); + + void Redirect(const void* parameters); + + void CompressAndAnswerPngImage(const void* parameters); + + void GetDicomForInstance(const void* parameters); + + void RestApiGet(const void* parameters); + + void RestApiPostPut(bool isPost, const void* parameters); + + void RestApiDelete(const void* parameters); + + void LookupResource(_OrthancPluginService service, + const void* parameters); + + void SendHttpStatusCode(const void* parameters); + + void SendUnauthorized(const void* parameters); + + void SendMethodNotAllowed(const void* parameters); + + void SetCookie(const void* parameters); + + public: + PluginsHttpHandler(ServerContext& context); + + virtual ~PluginsHttpHandler(); + + virtual bool Handle(HttpOutput& output, + HttpMethod method, + const UriComponents& uri, + const Arguments& headers, + const Arguments& getArguments, + const std::string& postData); + + virtual bool InvokeService(_OrthancPluginService service, + const void* parameters); + + void SignalStoredInstance(DicomInstanceToStore& instance, + const std::string& instanceId); + + void SetOrthancRestApi(OrthancRestApi& restApi); + }; +} diff -r ac6bd50a8c83 -r f739d3f6cfcf Plugins/Engine/PluginsHttpHandler.cpp --- a/Plugins/Engine/PluginsHttpHandler.cpp Mon Sep 08 17:34:33 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,819 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2014 Medical Physics Department, CHU of Liege, - * Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PluginsHttpHandler.h" - -#include "../../Core/ChunkedBuffer.h" -#include "../../Core/OrthancException.h" -#include "../../Core/Toolbox.h" -#include "../../Core/HttpServer/HttpOutput.h" -#include "../../Core/ImageFormats/PngWriter.h" -#include "../../OrthancServer/ServerToolbox.h" - -#include -#include - -namespace Orthanc -{ - namespace - { - // Anonymous namespace to avoid clashes between compilation modules - class StringHttpOutput : public IHttpOutputStream - { - private: - ChunkedBuffer buffer_; - - public: - void GetOutput(std::string& output) - { - buffer_.Flatten(output); - } - - virtual void OnHttpStatusReceived(HttpStatus status) - { - if (status != HttpStatus_200_Ok) - { - throw OrthancException(ErrorCode_BadRequest); - } - } - - virtual void Send(bool isHeader, const void* buffer, size_t length) - { - if (!isHeader) - { - buffer_.AddChunk(reinterpret_cast(buffer), length); - } - } - }; - } - - - - struct PluginsHttpHandler::PImpl - { - typedef std::pair RestCallback; - typedef std::list RestCallbacks; - typedef std::list OnStoredCallbacks; - - ServerContext& context_; - RestCallbacks restCallbacks_; - OrthancRestApi* restApi_; - OnStoredCallbacks onStoredCallbacks_; - - PImpl(ServerContext& context) : context_(context), restApi_(NULL) - { - } - }; - - - static char* CopyString(const std::string& str) - { - char *result = reinterpret_cast(malloc(str.size() + 1)); - if (result == NULL) - { - throw OrthancException(ErrorCode_NotEnoughMemory); - } - - if (str.size() == 0) - { - result[0] = '\0'; - } - else - { - memcpy(result, &str[0], str.size() + 1); - } - - return result; - } - - - PluginsHttpHandler::PluginsHttpHandler(ServerContext& context) - { - pimpl_.reset(new PImpl(context)); - } - - - PluginsHttpHandler::~PluginsHttpHandler() - { - for (PImpl::RestCallbacks::iterator it = pimpl_->restCallbacks_.begin(); - it != pimpl_->restCallbacks_.end(); ++it) - { - // Delete the regular expression associated with this callback - delete it->first; - } - } - - - static void ArgumentsToPlugin(std::vector& keys, - std::vector& values, - const HttpHandler::Arguments& arguments) - { - keys.resize(arguments.size()); - values.resize(arguments.size()); - - size_t pos = 0; - for (HttpHandler::Arguments::const_iterator - it = arguments.begin(); it != arguments.end(); ++it) - { - keys[pos] = it->first.c_str(); - values[pos] = it->second.c_str(); - pos++; - } - } - - - bool PluginsHttpHandler::Handle(HttpOutput& output, - HttpMethod method, - const UriComponents& uri, - const Arguments& headers, - const Arguments& getArguments, - const std::string& postData) - { - std::string flatUri = Toolbox::FlattenUri(uri); - OrthancPluginRestCallback callback = NULL; - - std::vector groups; - std::vector cgroups; - - // Loop over the callbacks registered by the plugins - bool found = false; - for (PImpl::RestCallbacks::const_iterator it = pimpl_->restCallbacks_.begin(); - it != pimpl_->restCallbacks_.end() && !found; ++it) - { - // Check whether the regular expression associated to this - // callback matches the URI - boost::cmatch what; - if (boost::regex_match(flatUri.c_str(), what, *(it->first))) - { - callback = it->second; - - // Extract the value of the free parameters of the regular expression - 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; - - std::vector getKeys, getValues, headersKeys, headersValues; - - OrthancPluginHttpRequest request; - memset(&request, 0, sizeof(OrthancPluginHttpRequest)); - - ArgumentsToPlugin(headersKeys, headersValues, headers); - - switch (method) - { - case HttpMethod_Get: - request.method = OrthancPluginHttpMethod_Get; - ArgumentsToPlugin(getKeys, getValues, getArguments); - break; - - case HttpMethod_Post: - request.method = OrthancPluginHttpMethod_Post; - break; - - case HttpMethod_Delete: - request.method = OrthancPluginHttpMethod_Delete; - break; - - case HttpMethod_Put: - request.method = OrthancPluginHttpMethod_Put; - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - - request.groups = (cgroups.size() ? &cgroups[0] : NULL); - request.groupsCount = cgroups.size(); - request.getCount = getArguments.size(); - request.body = (postData.size() ? &postData[0] : NULL); - request.bodySize = postData.size(); - request.headersCount = headers.size(); - - if (getArguments.size() > 0) - { - request.getKeys = &getKeys[0]; - request.getValues = &getValues[0]; - } - - if (headers.size() > 0) - { - request.headersKeys = &headersKeys[0]; - request.headersValues = &headersValues[0]; - } - - assert(callback != NULL); - int32_t error = callback(reinterpret_cast(&output), - flatUri.c_str(), - &request); - - if (error < 0) - { - LOG(ERROR) << "Plugin callback failed with error code " << error; - return false; - } - else - { - if (error > 0) - { - LOG(WARNING) << "Plugin callback finished with warning code " << error; - } - - return true; - } - } - - - void PluginsHttpHandler::SignalStoredInstance(DicomInstanceToStore& instance, - const std::string& instanceId) - { - for (PImpl::OnStoredCallbacks::const_iterator - callback = pimpl_->onStoredCallbacks_.begin(); - callback != pimpl_->onStoredCallbacks_.end(); ++callback) - { - (*callback) (reinterpret_cast(&instance), - instanceId.c_str()); - } - } - - - - static void CopyToMemoryBuffer(OrthancPluginMemoryBuffer& target, - const void* data, - size_t size) - { - target.size = size; - - if (size == 0) - { - target.data = NULL; - } - else - { - target.data = malloc(size); - if (target.data != NULL) - { - memcpy(target.data, data, size); - } - else - { - throw OrthancException(ErrorCode_NotEnoughMemory); - } - } - } - - - static void CopyToMemoryBuffer(OrthancPluginMemoryBuffer& target, - const std::string& str) - { - if (str.size() == 0) - { - target.size = 0; - target.data = NULL; - } - else - { - CopyToMemoryBuffer(target, str.c_str(), str.size()); - } - } - - - void PluginsHttpHandler::RegisterRestCallback(const void* parameters) - { - const _OrthancPluginRestCallback& p = - *reinterpret_cast(parameters); - - LOG(INFO) << "Plugin has registered a REST callback on: " << p.pathRegularExpression; - pimpl_->restCallbacks_.push_back(std::make_pair(new boost::regex(p.pathRegularExpression), p.callback)); - } - - - - void PluginsHttpHandler::RegisterOnStoredInstanceCallback(const void* parameters) - { - const _OrthancPluginOnStoredInstanceCallback& p = - *reinterpret_cast(parameters); - - LOG(INFO) << "Plugin has registered an OnStoredInstance callback"; - pimpl_->onStoredCallbacks_.push_back(p.callback); - } - - - - void PluginsHttpHandler::AnswerBuffer(const void* parameters) - { - const _OrthancPluginAnswerBuffer& p = - *reinterpret_cast(parameters); - - HttpOutput* translatedOutput = reinterpret_cast(p.output); - translatedOutput->SetContentType(p.mimeType); - translatedOutput->SendBody(p.answer, p.answerSize); - } - - - void PluginsHttpHandler::Redirect(const void* parameters) - { - const _OrthancPluginOutputPlusArgument& p = - *reinterpret_cast(parameters); - - HttpOutput* translatedOutput = reinterpret_cast(p.output); - translatedOutput->Redirect(p.argument); - } - - - void PluginsHttpHandler::SendHttpStatusCode(const void* parameters) - { - const _OrthancPluginSendHttpStatusCode& p = - *reinterpret_cast(parameters); - - HttpOutput* translatedOutput = reinterpret_cast(p.output); - translatedOutput->SendStatus(static_cast(p.status)); - } - - - void PluginsHttpHandler::SendUnauthorized(const void* parameters) - { - const _OrthancPluginOutputPlusArgument& p = - *reinterpret_cast(parameters); - - HttpOutput* translatedOutput = reinterpret_cast(p.output); - translatedOutput->SendUnauthorized(p.argument); - } - - - void PluginsHttpHandler::SendMethodNotAllowed(const void* parameters) - { - const _OrthancPluginOutputPlusArgument& p = - *reinterpret_cast(parameters); - - HttpOutput* translatedOutput = reinterpret_cast(p.output); - translatedOutput->SendMethodNotAllowed(p.argument); - } - - - void PluginsHttpHandler::SetCookie(const void* parameters) - { - const _OrthancPluginSetCookie& p = - *reinterpret_cast(parameters); - - HttpOutput* translatedOutput = reinterpret_cast(p.output); - translatedOutput->SetCookie(p.cookie, p.value); - } - - - void PluginsHttpHandler::CompressAndAnswerPngImage(const void* parameters) - { - const _OrthancPluginCompressAndAnswerPngImage& 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->SetContentType("image/png"); - translatedOutput->SendBody(png); - } - - - void PluginsHttpHandler::GetDicomForInstance(const void* parameters) - { - const _OrthancPluginGetDicomForInstance& p = - *reinterpret_cast(parameters); - - std::string dicom; - pimpl_->context_.ReadFile(dicom, p.instanceId, FileContentType_Dicom); - CopyToMemoryBuffer(*p.target, dicom); - } - - - void PluginsHttpHandler::RestApiGet(const void* parameters) - { - const _OrthancPluginRestApiGet& p = - *reinterpret_cast(parameters); - - HttpHandler::Arguments headers; // No HTTP header - std::string body; // No body for a GET request - - UriComponents uri; - HttpHandler::Arguments getArguments; - HttpHandler::ParseGetQuery(uri, getArguments, p.uri); - - StringHttpOutput stream; - HttpOutput http(stream, false /* no keep alive */); - - LOG(INFO) << "Plugin making REST GET call on URI " << p.uri; - - if (pimpl_->restApi_ != NULL && - pimpl_->restApi_->Handle(http, HttpMethod_Get, uri, headers, getArguments, body)) - { - std::string result; - stream.GetOutput(result); - CopyToMemoryBuffer(*p.target, result); - } - else - { - throw OrthancException(ErrorCode_BadRequest); - } - } - - - void PluginsHttpHandler::RestApiPostPut(bool isPost, const void* parameters) - { - const _OrthancPluginRestApiPostPut& p = - *reinterpret_cast(parameters); - - HttpHandler::Arguments headers; // No HTTP header - HttpHandler::Arguments getArguments; // No GET argument for POST/PUT - - UriComponents uri; - Toolbox::SplitUriComponents(uri, p.uri); - - // TODO Avoid unecessary memcpy - std::string body(p.body, p.bodySize); - - StringHttpOutput stream; - HttpOutput http(stream, false /* no keep alive */); - - HttpMethod method = (isPost ? HttpMethod_Post : HttpMethod_Put); - LOG(INFO) << "Plugin making REST " << EnumerationToString(method) << " call on URI " << p.uri; - - if (pimpl_->restApi_ != NULL && - pimpl_->restApi_->Handle(http, method, uri, headers, getArguments, body)) - { - std::string result; - stream.GetOutput(result); - CopyToMemoryBuffer(*p.target, result); - } - else - { - throw OrthancException(ErrorCode_BadRequest); - } - } - - - void PluginsHttpHandler::RestApiDelete(const void* parameters) - { - // The "parameters" point to the URI - UriComponents uri; - Toolbox::SplitUriComponents(uri, reinterpret_cast(parameters)); - - HttpHandler::Arguments headers; // No HTTP header - HttpHandler::Arguments getArguments; // No GET argument for POST/PUT - std::string body; // No body for DELETE - - StringHttpOutput stream; - HttpOutput http(stream, false /* no keep alive */); - - LOG(INFO) << "Plugin making REST DELETE call on URI " - << reinterpret_cast(parameters); - - if (pimpl_->restApi_ == NULL || - !pimpl_->restApi_->Handle(http, HttpMethod_Delete, uri, headers, getArguments, body)) - { - throw OrthancException(ErrorCode_BadRequest); - } - } - - - void PluginsHttpHandler::LookupResource(_OrthancPluginService service, - const void* parameters) - { - const _OrthancPluginLookupResource& p = - *reinterpret_cast(parameters); - - /** - * The enumeration below only uses the tags that are indexed in - * the Orthanc database. It reflects the - * "CandidateResources::ApplyFilter()" method of the - * "OrthancFindRequestHandler" class. - **/ - - DicomTag tag(0, 0); - ResourceType level; - switch (service) - { - case _OrthancPluginService_LookupPatient: - tag = DICOM_TAG_PATIENT_ID; - level = ResourceType_Patient; - break; - - case _OrthancPluginService_LookupStudy: - tag = DICOM_TAG_STUDY_INSTANCE_UID; - level = ResourceType_Study; - break; - - case _OrthancPluginService_LookupStudyWithAccessionNumber: - tag = DICOM_TAG_ACCESSION_NUMBER; - level = ResourceType_Study; - break; - - case _OrthancPluginService_LookupSeries: - tag = DICOM_TAG_SERIES_INSTANCE_UID; - level = ResourceType_Series; - break; - - case _OrthancPluginService_LookupInstance: - tag = DICOM_TAG_SOP_INSTANCE_UID; - level = ResourceType_Instance; - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - std::list result; - pimpl_->context_.GetIndex().LookupTagValue(result, tag, p.identifier, level); - - if (result.size() == 1) - { - *p.result = CopyString(result.front()); - } - else - { - throw OrthancException(ErrorCode_UnknownResource); - } - } - - - static void AccessInstanceMetadataInternal(bool checkExistence, - const _OrthancPluginAccessDicomInstance& params, - const DicomInstanceToStore& instance) - { - MetadataType metadata; - - try - { - metadata = StringToMetadata(params.key); - } - catch (OrthancException&) - { - // Unknown metadata - if (checkExistence) - { - *params.resultInt64 = -1; - } - else - { - *params.resultString = NULL; - } - - return; - } - - ServerIndex::MetadataMap::const_iterator it = - instance.GetMetadata().find(std::make_pair(ResourceType_Instance, metadata)); - - if (checkExistence) - { - if (it != instance.GetMetadata().end()) - { - *params.resultInt64 = 1; - } - else - { - *params.resultInt64 = 0; - } - } - else - { - if (it != instance.GetMetadata().end()) - { - *params.resultString = it->second.c_str(); - } - else - { - // Error: Missing metadata - *params.resultString = NULL; - } - } - } - - - static void AccessDicomInstance(_OrthancPluginService service, - const void* parameters) - { - const _OrthancPluginAccessDicomInstance& p = - *reinterpret_cast(parameters); - - DicomInstanceToStore& instance = - *reinterpret_cast(p.instance); - - switch (service) - { - case _OrthancPluginService_GetInstanceRemoteAet: - *p.resultString = instance.GetRemoteAet().c_str(); - return; - - case _OrthancPluginService_GetInstanceSize: - *p.resultInt64 = instance.GetBufferSize(); - return; - - case _OrthancPluginService_GetInstanceData: - *p.resultString = instance.GetBufferData(); - return; - - case _OrthancPluginService_HasInstanceMetadata: - AccessInstanceMetadataInternal(true, p, instance); - return; - - case _OrthancPluginService_GetInstanceMetadata: - AccessInstanceMetadataInternal(false, p, instance); - return; - - case _OrthancPluginService_GetInstanceJson: - case _OrthancPluginService_GetInstanceSimplifiedJson: - { - Json::StyledWriter writer; - std::string s; - - if (service == _OrthancPluginService_GetInstanceJson) - { - s = writer.write(instance.GetJson()); - } - else - { - Json::Value simplified; - SimplifyTags(simplified, instance.GetJson()); - s = writer.write(simplified); - } - - *p.resultStringToFree = CopyString(s); - return; - } - - default: - throw OrthancException(ErrorCode_InternalError); - } - } - - - bool PluginsHttpHandler::InvokeService(_OrthancPluginService service, - const void* parameters) - { - switch (service) - { - case _OrthancPluginService_RegisterRestCallback: - RegisterRestCallback(parameters); - return true; - - case _OrthancPluginService_RegisterOnStoredInstanceCallback: - RegisterOnStoredInstanceCallback(parameters); - return true; - - case _OrthancPluginService_AnswerBuffer: - AnswerBuffer(parameters); - return true; - - case _OrthancPluginService_CompressAndAnswerPngImage: - CompressAndAnswerPngImage(parameters); - return true; - - case _OrthancPluginService_GetDicomForInstance: - GetDicomForInstance(parameters); - return true; - - case _OrthancPluginService_RestApiGet: - RestApiGet(parameters); - return true; - - case _OrthancPluginService_RestApiPost: - RestApiPostPut(true, parameters); - return true; - - case _OrthancPluginService_RestApiDelete: - RestApiDelete(parameters); - return true; - - case _OrthancPluginService_RestApiPut: - RestApiPostPut(false, parameters); - return true; - - case _OrthancPluginService_Redirect: - Redirect(parameters); - return true; - - case _OrthancPluginService_SendUnauthorized: - SendUnauthorized(parameters); - return true; - - case _OrthancPluginService_SendMethodNotAllowed: - SendMethodNotAllowed(parameters); - return true; - - case _OrthancPluginService_SendHttpStatusCode: - SendHttpStatusCode(parameters); - return true; - - case _OrthancPluginService_SetCookie: - SetCookie(parameters); - return true; - - case _OrthancPluginService_LookupPatient: - case _OrthancPluginService_LookupStudy: - case _OrthancPluginService_LookupStudyWithAccessionNumber: - case _OrthancPluginService_LookupSeries: - case _OrthancPluginService_LookupInstance: - LookupResource(service, parameters); - return true; - - case _OrthancPluginService_GetInstanceRemoteAet: - case _OrthancPluginService_GetInstanceSize: - case _OrthancPluginService_GetInstanceData: - case _OrthancPluginService_GetInstanceJson: - case _OrthancPluginService_GetInstanceSimplifiedJson: - case _OrthancPluginService_HasInstanceMetadata: - case _OrthancPluginService_GetInstanceMetadata: - AccessDicomInstance(service, parameters); - return true; - - default: - return false; - } - } - - - void PluginsHttpHandler::SetOrthancRestApi(OrthancRestApi& restApi) - { - pimpl_->restApi_ = &restApi; - } - -} diff -r ac6bd50a8c83 -r f739d3f6cfcf Plugins/Engine/PluginsHttpHandler.h --- a/Plugins/Engine/PluginsHttpHandler.h Mon Sep 08 17:34:33 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,102 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2014 Medical Physics Department, CHU of Liege, - * Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "PluginsManager.h" -#include "../../Core/HttpServer/HttpHandler.h" -#include "../../OrthancServer/ServerContext.h" -#include "../../OrthancServer/OrthancRestApi/OrthancRestApi.h" -#include "../OrthancCPlugin/OrthancCPlugin.h" - -#include -#include - -namespace Orthanc -{ - class PluginsHttpHandler : public HttpHandler, public IPluginServiceProvider - { - private: - struct PImpl; - - boost::shared_ptr pimpl_; - - void RegisterRestCallback(const void* parameters); - - void RegisterOnStoredInstanceCallback(const void* parameters); - - void AnswerBuffer(const void* parameters); - - void Redirect(const void* parameters); - - void CompressAndAnswerPngImage(const void* parameters); - - void GetDicomForInstance(const void* parameters); - - void RestApiGet(const void* parameters); - - void RestApiPostPut(bool isPost, const void* parameters); - - void RestApiDelete(const void* parameters); - - void LookupResource(_OrthancPluginService service, - const void* parameters); - - void SendHttpStatusCode(const void* parameters); - - void SendUnauthorized(const void* parameters); - - void SendMethodNotAllowed(const void* parameters); - - void SetCookie(const void* parameters); - - public: - PluginsHttpHandler(ServerContext& context); - - virtual ~PluginsHttpHandler(); - - virtual bool Handle(HttpOutput& output, - HttpMethod method, - const UriComponents& uri, - const Arguments& headers, - const Arguments& getArguments, - const std::string& postData); - - virtual bool InvokeService(_OrthancPluginService service, - const void* parameters); - - void SignalStoredInstance(DicomInstanceToStore& instance, - const std::string& instanceId); - - void SetOrthancRestApi(OrthancRestApi& restApi); - }; -}