changeset 1882:5cf2bd0abfa2

OrthancPluginSendMultipartItem2 for DICOMweb
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 09 Dec 2015 09:29:05 +0100
parents d2efbe076653
children 71356f41ec2f
files Core/HttpServer/HttpOutput.cpp Core/HttpServer/HttpOutput.h NEWS Plugins/Engine/OrthancPlugins.cpp Plugins/Engine/OrthancPlugins.h Plugins/Include/orthanc/OrthancCPlugin.h
diffstat 6 files changed, 160 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/Core/HttpServer/HttpOutput.cpp	Tue Dec 08 15:53:35 2015 +0100
+++ b/Core/HttpServer/HttpOutput.cpp	Wed Dec 09 09:29:05 2015 +0100
@@ -449,12 +449,59 @@
   }
 
 
-  void HttpOutput::StateMachine::SendMultipartItem(const void* item, size_t length)
+  void HttpOutput::StateMachine::SendMultipartItem(const void* item, 
+                                                   size_t length,
+                                                   const std::map<std::string, std::string>& headers)
   {
+    if (state_ != State_WritingMultipart)
+    {
+      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+    }
+
     std::string header = "--" + multipartBoundary_ + "\r\n";
-    header += "Content-Type: " + multipartContentType_ + "\r\n";
-    header += "Content-Length: " + boost::lexical_cast<std::string>(length) + "\r\n";
-    header += "MIME-Version: 1.0\r\n\r\n";
+
+    bool hasContentType = false;
+    bool hasContentLength = false;
+    bool hasMimeVersion = false;
+
+    for (std::map<std::string, std::string>::const_iterator
+           it = headers.begin(); it != headers.end(); ++it)
+    {
+      header += it->first + ": " + it->second + "\r\n";
+
+      std::string tmp;
+      Toolbox::ToLowerCase(tmp, it->first);
+
+      if (tmp == "content-type")
+      {
+        hasContentType = true;
+      }
+
+      if (tmp == "content-length")
+      {
+        hasContentLength = true;
+      }
+
+      if (tmp == "mime-version")
+      {
+        hasMimeVersion = true;
+      }
+    }
+
+    if (!hasContentType)
+    {
+      header += "Content-Type: " + multipartContentType_ + "\r\n";
+    }
+
+    if (!hasContentLength)
+    {
+      header += "Content-Length: " + boost::lexical_cast<std::string>(length) + "\r\n";
+    }
+
+    if (!hasMimeVersion)
+    {
+      header += "MIME-Version: 1.0\r\n\r\n";
+    }
 
     stream_.Send(false, header.c_str(), header.size());
 
@@ -463,7 +510,7 @@
       stream_.Send(false, item, length);
     }
 
-    stream_.Send(false, "\r\n", 2);
+    stream_.Send(false, "\r\n", 2);    
   }
 
 
@@ -489,19 +536,6 @@
   }
 
 
-  void HttpOutput::SendMultipartItem(const std::string& item)
-  {
-    if (item.size() > 0)
-    {
-      stateMachine_.SendMultipartItem(item.c_str(), item.size());
-    }
-    else
-    {
-      stateMachine_.SendMultipartItem(NULL, 0);
-    }
-  }
-
-
   void HttpOutput::Answer(IHttpStreamAnswer& stream)
   {
     HttpCompression compression = stream.SetupHttpCompression(isGzipAllowed_, isDeflateAllowed_);
--- a/Core/HttpServer/HttpOutput.h	Tue Dec 08 15:53:35 2015 +0100
+++ b/Core/HttpServer/HttpOutput.h	Wed Dec 09 09:29:05 2015 +0100
@@ -99,7 +99,9 @@
       void StartMultipart(const std::string& subType,
                           const std::string& contentType);
 
-      void SendMultipartItem(const void* item, size_t length);
+      void SendMultipartItem(const void* item, 
+                             size_t length,
+                             const std::map<std::string, std::string>& headers);
 
       void CloseMultipart();
 
@@ -202,11 +204,11 @@
       stateMachine_.StartMultipart(subType, contentType);
     }
 
-    void SendMultipartItem(const std::string& item);
-
-    void SendMultipartItem(const void* item, size_t size)
+    void SendMultipartItem(const void* item, 
+                           size_t size,
+                           const std::map<std::string, std::string>& headers)
     {
-      stateMachine_.SendMultipartItem(item, size);
+      stateMachine_.SendMultipartItem(item, size, headers);
     }
 
     void CloseMultipart()
--- a/NEWS	Tue Dec 08 15:53:35 2015 +0100
+++ b/NEWS	Wed Dec 09 09:29:05 2015 +0100
@@ -2,6 +2,9 @@
 ===============================
 
 
+* New function in plugin SDK: "OrthancPluginSendMultipartItem2()"
+
+
 Version 0.9.6 (2015/12/08)
 ==========================
 
--- a/Plugins/Engine/OrthancPlugins.cpp	Tue Dec 08 15:53:35 2015 +0100
+++ b/Plugins/Engine/OrthancPlugins.cpp	Wed Dec 09 09:29:05 2015 +0100
@@ -1574,7 +1574,39 @@
 
     *(p.target) = ReturnImage(result);
   }
-        
+
+
+  void OrthancPlugins::ApplySendMultipartItem(const void* parameters)
+  {
+    // An exception might be raised in this function if the
+    // connection was closed by the HTTP client.
+    const _OrthancPluginAnswerBuffer& p =
+      *reinterpret_cast<const _OrthancPluginAnswerBuffer*>(parameters);
+
+    HttpOutput* output = reinterpret_cast<HttpOutput*>(p.output);
+
+    std::map<std::string, std::string> headers;  // No custom headers
+    output->SendMultipartItem(p.answer, p.answerSize, headers);
+  }
+
+
+  void OrthancPlugins::ApplySendMultipartItem2(const void* parameters)
+  {
+    // An exception might be raised in this function if the
+    // connection was closed by the HTTP client.
+    const _OrthancPluginSendMultipartItem2& p =
+      *reinterpret_cast<const _OrthancPluginSendMultipartItem2*>(parameters);
+    HttpOutput* output = reinterpret_cast<HttpOutput*>(p.output);
+    
+    std::map<std::string, std::string> headers;
+    for (uint32_t i = 0; i < p.headersCount; i++)
+    {
+      headers[p.headersKeys[i]] = p.headersValues[i];
+    }
+    
+    output->SendMultipartItem(p.answer, p.answerSize, headers);
+  }
+      
 
   void OrthancPlugins::DatabaseAnswer(const void* parameters)
   {
@@ -1969,15 +2001,12 @@
       }
 
       case _OrthancPluginService_SendMultipartItem:
-      {
-        // An exception might be raised in this function if the
-        // connection was closed by the HTTP client.
-        const _OrthancPluginAnswerBuffer& p =
-          *reinterpret_cast<const _OrthancPluginAnswerBuffer*>(parameters);
-        HttpOutput* output = reinterpret_cast<HttpOutput*>(p.output);
-        output->SendMultipartItem(p.answer, p.answerSize);
+        ApplySendMultipartItem(parameters);
         return true;
-      }
+
+      case _OrthancPluginService_SendMultipartItem2:
+        ApplySendMultipartItem2(parameters);
+        return true;
 
       case _OrthancPluginService_ReadFile:
       {
--- a/Plugins/Engine/OrthancPlugins.h	Tue Dec 08 15:53:35 2015 +0100
+++ b/Plugins/Engine/OrthancPlugins.h	Wed Dec 09 09:29:05 2015 +0100
@@ -152,6 +152,10 @@
 
     void ApplyLookupDictionary(const void* parameters);
 
+    void ApplySendMultipartItem(const void* parameters);
+
+    void ApplySendMultipartItem2(const void* parameters);
+
     void ComputeHash(_OrthancPluginService service,
                      const void* parameters);
 
--- a/Plugins/Include/orthanc/OrthancCPlugin.h	Tue Dec 08 15:53:35 2015 +0100
+++ b/Plugins/Include/orthanc/OrthancCPlugin.h	Wed Dec 09 09:29:05 2015 +0100
@@ -114,7 +114,7 @@
 
 #define ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER     0
 #define ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER     9
-#define ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER  5
+#define ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER  7
 
 
 
@@ -424,6 +424,7 @@
     _OrthancPluginService_SendMultipartItem = 2009,
     _OrthancPluginService_SendHttpStatus = 2010,
     _OrthancPluginService_CompressAndAnswerImage = 2011,
+    _OrthancPluginService_SendMultipartItem2 = 2012,
 
     /* Access to the Orthanc database and API */
     _OrthancPluginService_GetDicomForInstance = 3000,
@@ -2719,7 +2720,7 @@
    * @param subType The sub-type of the multipart answer ("mixed" or "related").
    * @param contentType The MIME type of the items in the multipart answer.
    * @return 0 if success, or the error code if failure.
-   * @see OrthancPluginSendMultipartItem()
+   * @see OrthancPluginSendMultipartItem(), OrthancPluginSendMultipartItem2()
    * @ingroup REST
    **/
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginStartMultipartAnswer(
@@ -2748,6 +2749,7 @@
    * @param answerSize Number of bytes of the item.
    * @return 0 if success, or the error code if failure (this notably happens
    * if the connection is closed by the client).
+   * @see OrthancPluginSendMultipartItem2()
    * @ingroup REST
    **/
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginSendMultipartItem(
@@ -4677,6 +4679,58 @@
   }
 
 
+
+  typedef struct
+  {
+    OrthancPluginRestOutput* output;
+    const char*              answer;
+    uint32_t                 answerSize;
+    uint32_t                 headersCount;
+    const char* const*       headersKeys;
+    const char* const*       headersValues;
+  } _OrthancPluginSendMultipartItem2;
+
+  /**
+   * @brief Send an item as a part of some HTTP multipart answer, with custom headers.
+   *
+   * This function sends an item as a part of some HTTP multipart
+   * answer that was initiated by OrthancPluginStartMultipartAnswer(). In addition to
+   * OrthancPluginSendMultipartItem(), this function will set HTTP header associated
+   * with the item.
+   * 
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param output The HTTP connection to the client application.
+   * @param answer Pointer to the memory buffer containing the item.
+   * @param answerSize Number of bytes of the item.
+   * @param headersCount The number of HTTP headers.
+   * @param headersKeys Array containing the keys of the HTTP headers.
+   * @param headersValues Array containing the values of the HTTP headers.
+   * @return 0 if success, or the error code if failure (this notably happens
+   * if the connection is closed by the client).
+   * @see OrthancPluginSendMultipartItem()
+   * @ingroup REST
+   **/
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginSendMultipartItem2(
+    OrthancPluginContext*    context,
+    OrthancPluginRestOutput* output,
+    const char*              answer,
+    uint32_t                 answerSize,
+    uint32_t                 headersCount,
+    const char* const*       headersKeys,
+    const char* const*       headersValues)
+  {
+    _OrthancPluginSendMultipartItem2 params;
+    params.output = output;
+    params.answer = answer;
+    params.answerSize = answerSize;
+    params.headersCount = headersCount;
+    params.headersKeys = headersKeys;
+    params.headersValues = headersValues;    
+
+    return context->InvokeService(context, _OrthancPluginService_SendMultipartItem2, &params);
+  }
+
+
 #ifdef  __cplusplus
 }
 #endif