comparison Plugins/Samples/Common/OrthancPluginCppWrapper.cpp @ 3407:b7728227a852

C++ wrappers: compatibility mode if missing OrthancPluginRegisterMultipartRestCallback()
author Sebastien Jodogne <s.jodogne@gmail.com>
date Sat, 08 Jun 2019 11:57:46 +0200
parents 408ffcb4038f
children 3575466a3e57
comparison
equal deleted inserted replaced
3406:8de071691d13 3407:b7728227a852
31 **/ 31 **/
32 32
33 33
34 #include "OrthancPluginCppWrapper.h" 34 #include "OrthancPluginCppWrapper.h"
35 35
36 #if HAS_ORTHANC_PLUGIN_HTTP_MULTIPART_SERVER == 0
37 # if ORTHANC_FRAMEWORK_VERSION_IS_ABOVE(1, 5, 7)
38 # define HAS_ORTHANC_FRAMEWORK_MULTIPART_READER 1
39 # include "../../../Core/HttpServer/MultipartStreamReader.h"
40 # include <boost/thread/shared_mutex.hpp>
41 # else
42 # define HAS_ORTHANC_FRAMEWORK_MULTIPART_READER 0
43 # endif
44 #endif
45
46
36 #include <boost/algorithm/string/predicate.hpp> 47 #include <boost/algorithm/string/predicate.hpp>
37 #include <json/reader.h> 48 #include <json/reader.h>
38 #include <json/writer.h> 49 #include <json/writer.h>
39 50
40 51
2742 OrthancPluginRegisterMultipartRestCallback( 2753 OrthancPluginRegisterMultipartRestCallback(
2743 GetGlobalContext(), regularExpression.c_str(), 2754 GetGlobalContext(), regularExpression.c_str(),
2744 reinterpret_cast<OrthancPluginMultipartRestFactory*>(this), 2755 reinterpret_cast<OrthancPluginMultipartRestFactory*>(this),
2745 MultipartRestFactory, MultipartRestAddPart, MultipartRestExecute, MultipartRestFinalize); 2756 MultipartRestFactory, MultipartRestAddPart, MultipartRestExecute, MultipartRestFinalize);
2746 } 2757 }
2758
2759 #elif HAS_ORTHANC_FRAMEWORK_MULTIPART_READER == 1
2760
2761 namespace
2762 {
2763 class CompatibilityPartHandler : public Orthanc::MultipartStreamReader::IHandler
2764 {
2765 private:
2766 MultipartRestCallback::IHandler& handler_;
2767
2768 public:
2769 CompatibilityPartHandler(MultipartRestCallback::IHandler& handler) :
2770 handler_(handler)
2771 {
2772 }
2773
2774 virtual void HandlePart(const Orthanc::MultipartStreamReader::HttpHeaders& headers,
2775 const void* part,
2776 size_t size)
2777 {
2778 std::string contentType;
2779 if (!Orthanc::MultipartStreamReader::GetMainContentType(contentType, headers))
2780 {
2781 contentType.clear();
2782 }
2783
2784 OrthancPluginErrorCode code = handler_.AddPart(contentType, headers, part, size);
2785
2786 if (code != OrthancPluginErrorCode_Success)
2787 {
2788 ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
2789 }
2790 }
2791 };
2792 }
2793
2794 static boost::shared_mutex compatibilityMultipartMutex_;
2795 static std::set<MultipartRestCallback*> compatibilityMultipartCallbacks_;
2796
2797
2798 namespace
2799 {
2800 void CompatibilityMultipartRestCallback(OrthancPluginRestOutput* output,
2801 const char* url,
2802 const OrthancPluginHttpRequest* request)
2803 {
2804 std::map<std::string, std::string> headers;
2805 for (uint32_t i = 0; i < request->headersCount; i++)
2806 {
2807 headers[request->headersKeys[i]] = request->headersValues[i];
2808 }
2809
2810 std::string mainContentType;
2811 if (!Orthanc::MultipartStreamReader::GetMainContentType(mainContentType, headers))
2812 {
2813 LogError("Missing Content-Type HTTP header, prevents streaming the body");
2814 ORTHANC_PLUGINS_THROW_EXCEPTION(UnsupportedMediaType);
2815 }
2816
2817 std::string contentType, subType, boundary;
2818 if (!Orthanc::MultipartStreamReader::ParseMultipartContentType
2819 (contentType, subType, boundary, mainContentType))
2820 {
2821 LogError("Invalid Content-Type HTTP header, prevents streaming the body: \"" +
2822 mainContentType + "\"");
2823 ORTHANC_PLUGINS_THROW_EXCEPTION(UnsupportedMediaType);
2824 }
2825
2826 std::vector<std::string> groups;
2827 groups.reserve(request->groupsCount);
2828 for (uint32_t i = 0; i < request->groupsCount; i++)
2829 {
2830 groups[i] = request->groups[i];
2831 }
2832
2833 std::auto_ptr<MultipartRestCallback::IHandler> handler;
2834
2835 {
2836 boost::shared_lock<boost::shared_mutex> lock(compatibilityMultipartMutex_);
2837
2838 for (std::set<MultipartRestCallback*>::const_iterator
2839 it = compatibilityMultipartCallbacks_.begin();
2840 it != compatibilityMultipartCallbacks_.end(); ++it)
2841 {
2842 assert(*it != NULL);
2843 handler.reset((*it)->CreateHandler(request->method, url, contentType, subType, groups, headers));
2844 if (handler.get() != NULL)
2845 {
2846 break;
2847 }
2848 }
2849 }
2850
2851 if (handler.get() != NULL)
2852 {
2853 {
2854 CompatibilityPartHandler wrapper(*handler);
2855 Orthanc::MultipartStreamReader reader(boundary);
2856 reader.SetHandler(wrapper);
2857 reader.AddChunk(request->body, request->bodySize);
2858 reader.CloseStream();
2859 }
2860
2861 handler->Execute(output);
2862 }
2863 }
2864 }
2865
2866 void MultipartRestCallback::Register(const std::string& regularExpression)
2867 {
2868 LogWarning("Performance warning: The plugin was compiled against a pre-1.5.7 version "
2869 "of the Orthanc SDK. Multipart transfers will be entirely stored in RAM.");
2870
2871 {
2872 boost::unique_lock<boost::shared_mutex> lock(compatibilityMultipartMutex_);
2873 compatibilityMultipartCallbacks_.insert(this);
2874 }
2875
2876 OrthancPluginRegisterRestCallback(GetGlobalContext(), regularExpression.c_str(),
2877 Internals::Protect<CompatibilityMultipartRestCallback>);
2878 }
2879
2880
2881 #else
2882
2883 void MultipartRestCallback::Register(const std::string& regularExpression)
2884 {
2885 /**
2886 * Version >= 1.5.7 of the Orthanc framework must be
2887 * available. Make sure that macros
2888 * "ORTHANC_FRAMEWORK_VERSION_MAJOR",
2889 * "ORTHANC_FRAMEWORK_VERSION_MINOR" and
2890 * "ORTHANC_FRAMEWORK_VERSION_REVISION" are properly set.
2891 **/
2892 LogError("The compatibility mode for multipart transfers is not available.");
2893 ORTHANC_PLUGINS_THROW_EXCEPTION(NotImplemented);
2894 }
2895
2747 #endif 2896 #endif
2748 2897
2749 } 2898 }