diff Plugins/Samples/Common/OrthancPluginCppWrapper.h @ 3414:b9cba6a91780

simplification
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 11 Jun 2019 19:44:10 +0200
parents f09bfdea3fc3
children 2a821deece64
line wrap: on
line diff
--- a/Plugins/Samples/Common/OrthancPluginCppWrapper.h	Tue Jun 11 14:02:57 2019 +0200
+++ b/Plugins/Samples/Common/OrthancPluginCppWrapper.h	Tue Jun 11 19:44:10 2019 +0200
@@ -57,21 +57,6 @@
 #endif
 
 
-#if !defined(ORTHANC_FRAMEWORK_VERSION_IS_ABOVE)
-#define ORTHANC_FRAMEWORK_VERSION_IS_ABOVE(major, minor, revision)      \
-  (defined(HAS_ORTHANC_FRAMEWORK) &&                                    \
-   defined(ORTHANC_FRAMEWORK_VERSION_MAJOR) &&                          \
-   defined(ORTHANC_FRAMEWORK_VERSION_MINOR) &&                          \
-   defined(ORTHANC_FRAMEWORK_VERSION_REVISION) &&                       \
-   HAS_ORTHANC_FRAMEWORK == 1 &&                                        \
-   ORTHANC_FRAMEWORK_VERSION_MAJOR > major ||                           \
-   (ORTHANC_FRAMEWORK_VERSION_MAJOR == major &&                         \
-    (ORTHANC_FRAMEWORK_VERSION_MINOR > minor ||                         \
-     (ORTHANC_FRAMEWORK_VERSION_MINOR == minor &&                       \
-      ORTHANC_FRAMEWORK_VERSION_REVISION >= revision))))
-#endif
-
-
 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 2, 0)
 // The "OrthancPluginFindMatcher()" primitive was introduced in Orthanc 1.2.0
 #  define HAS_ORTHANC_PLUGIN_FIND_MATCHER  1
@@ -113,9 +98,9 @@
 #endif
 
 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 7)
-#  define HAS_ORTHANC_PLUGIN_HTTP_MULTIPART_SERVER  1
+#  define HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER  1
 #else
-#  define HAS_ORTHANC_PLUGIN_HTTP_MULTIPART_SERVER  0
+#  define HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER  0
 #endif
 
 
@@ -126,7 +111,6 @@
                                 const char* url,
                                 const OrthancPluginHttpRequest* request);
 
-
   void SetGlobalContext(OrthancPluginContext* context);
 
   bool HasGlobalContext();
@@ -936,36 +920,225 @@
 
 
 
-  class MultipartRestCallback : public boost::noncopyable
+  class IChunkedRequestReader : public boost::noncopyable
   {
   public:
-    class IHandler : public boost::noncopyable
-    {
-    public:
-      virtual ~IHandler()
-      {
-      }
-
-      virtual OrthancPluginErrorCode AddPart(const std::string& contentType,
-                                             const std::map<std::string, std::string>& headers,
-                                             const void* data,
-                                             size_t size) = 0;
-
-      virtual OrthancPluginErrorCode Execute(OrthancPluginRestOutput* output) = 0;
-    };
-
-
-    virtual ~MultipartRestCallback()
+    virtual ~IChunkedRequestReader()
     {
     }
 
-    virtual IHandler* CreateHandler(OrthancPluginHttpMethod method,
-                                    const std::string& url,
-                                    const std::string& contentType,
-                                    const std::string& subType,  // Possibly empty
-                                    const std::vector<std::string>& groups,
-                                    const std::map<std::string, std::string>& headers) = 0;
+    virtual void AddChunk(const void* data,
+                          size_t size) = 0;
+
+    virtual void Execute(OrthancPluginRestOutput* output) = 0;
+  };
+
+
+  typedef IChunkedRequestReader* (*ChunkedRestCallback) (OrthancPluginRestOutput* output,
+                                                         const char* url,
+                                                         const OrthancPluginHttpRequest* request);
+
+
+  namespace Internals
+  {
+#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER == 1
+    template <ChunkedRestCallback Callback>
+    OrthancPluginErrorCode Protect(OrthancPluginRestOutput* output,
+                                   OrthancPluginServerChunkedRequestReader** reader,
+                                   const char* url,
+                                   const OrthancPluginHttpRequest* request)
+    {
+      try
+      {
+        switch (request->method)
+        {
+          case OrthancPluginHttpMethod_Get:
+          case OrthancPluginHttpMethod_Delete:
+            if (output == NULL ||
+                reader != NULL ||
+                Callback(output, url, request) != NULL)
+            {
+              return OrthancPluginErrorCode_InternalError;
+            }
+
+            return OrthancPluginErrorCode_Success;
+
+          case OrthancPluginHttpMethod_Post:
+          case OrthancPluginHttpMethod_Put:
+            if (output != NULL ||
+                reader == NULL)
+            {
+              return OrthancPluginErrorCode_InternalError;
+            }
+            else
+            {
+              *reader = reinterpret_cast<OrthancPluginServerChunkedRequestReader*>(Callback(NULL, url, request));
+              if (*reader == NULL)
+              {
+                return OrthancPluginErrorCode_Plugin;
+              }
+            }
+
+            return OrthancPluginErrorCode_Success;
+
+          default:
+            return OrthancPluginErrorCode_InternalError;
+        }
+      }
+      catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e)
+      {
+#if HAS_ORTHANC_EXCEPTION == 1 && HAS_ORTHANC_PLUGIN_EXCEPTION_DETAILS == 1
+        if (HasGlobalContext() &&
+            e.HasDetails())
+        {
+          // The "false" instructs Orthanc not to log the detailed
+          // error message. This is to avoid duplicating the details,
+          // because "OrthancException" already does it on construction.
+          OrthancPluginSetHttpErrorDetails
+            (GetGlobalContext(), output, e.GetDetails(), false);
+        }
+#endif
+
+        return static_cast<OrthancPluginErrorCode>(e.GetErrorCode());
+      }
+      catch (boost::bad_lexical_cast&)
+      {
+        return OrthancPluginErrorCode_BadFileFormat;
+      }
+      catch (...)
+      {
+        return OrthancPluginErrorCode_Plugin;
+      }
+    }
+
+    static OrthancPluginErrorCode ChunkedRequestReaderAddChunk(
+      OrthancPluginServerChunkedRequestReader* reader,
+      const void*                              data,
+      uint32_t                                 size)
+    {
+      try
+      {
+        if (reader == NULL)
+        {
+          return OrthancPluginErrorCode_InternalError;
+        }
 
-    void Register(const std::string& regularExpression);
-  };
+        reinterpret_cast<IChunkedRequestReader*>(reader)->AddChunk(data, size);
+        return OrthancPluginErrorCode_Success;
+      }
+      catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e)
+      {
+        return static_cast<OrthancPluginErrorCode>(e.GetErrorCode());
+      }
+      catch (boost::bad_lexical_cast&)
+      {
+        return OrthancPluginErrorCode_BadFileFormat;
+      }
+      catch (...)
+      {
+        return OrthancPluginErrorCode_Plugin;
+      }
+    }
+
+    static OrthancPluginErrorCode ChunkedRequestReaderExecute(
+      OrthancPluginServerChunkedRequestReader* reader,
+      OrthancPluginRestOutput*                 output)
+    {
+      try
+      {
+        if (reader == NULL)
+        {
+          return OrthancPluginErrorCode_InternalError;
+        }
+
+        reinterpret_cast<IChunkedRequestReader*>(reader)->Execute(output);
+        return OrthancPluginErrorCode_Success;
+      }
+      catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e)
+      {
+        return static_cast<OrthancPluginErrorCode>(e.GetErrorCode());
+      }
+      catch (boost::bad_lexical_cast&)
+      {
+        return OrthancPluginErrorCode_BadFileFormat;
+      }
+      catch (...)
+      {
+        return OrthancPluginErrorCode_Plugin;
+      }
+    }
+
+    static void ChunkedRequestReaderFinalize(
+      OrthancPluginServerChunkedRequestReader* reader)
+    {
+      if (reader != NULL)
+      {
+        delete reinterpret_cast<IChunkedRequestReader*>(reader);
+      }
+    }
+
+#else
+
+    template <ChunkedRestCallback Callback>
+    void ChunkedRestCompatibility(OrthancPluginRestOutput* output,
+                                  const char* url,
+                                  const OrthancPluginHttpRequest* request)
+    {
+      switch (request->method)
+      {
+        case OrthancPluginHttpMethod_Get:
+        case OrthancPluginHttpMethod_Delete:
+          if (Callback(output, url, request) != NULL)
+          {
+            ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError);
+          }
+          else
+          {
+            return;
+          }
+
+        case OrthancPluginHttpMethod_Post:
+        case OrthancPluginHttpMethod_Put:
+        {
+          std::auto_ptr<IChunkedRequestReader> reader(Callback(NULL, url, request));
+          if (reader.get() == NULL)
+          {
+            ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError);
+          }
+          else
+          {
+            if (request->bodySize != 0)
+            {
+              reader->AddChunk(request->body, request->bodySize);
+            }
+            reader->Execute(output);
+          }
+          return;
+        }
+
+        default:
+          ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError);
+      }
+    }
+#endif
+  }
+
+
+  template <ChunkedRestCallback Callback>
+  void RegisterChunkedRestCallback(const std::string& uri)
+  {
+#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER == 1
+    OrthancPluginRegisterChunkedRestCallback(
+      GetGlobalContext(), uri.c_str(), Internals::Protect<Callback>,
+      Internals::ChunkedRequestReaderAddChunk,
+      Internals::ChunkedRequestReaderExecute,
+      Internals::ChunkedRequestReaderFinalize);
+#else
+    LogWarning("Performance warning: The plugin was compiled against a pre-1.5.7 version "
+               "of the Orthanc SDK. Multipart transfers will be entirely stored in RAM.");
+    OrthancPluginRegisterRestCallback(
+      GetGlobalContext(), uri.c_str(), 
+      Internals::Protect< Internals::ChunkedRestCompatibility<Callback> >);
+#endif
+  }
 }