diff Plugins/Engine/OrthancPlugins.cpp @ 3393:2cd0369a156f

support of chunked answers in HttpClient and in SDK
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 06 Jun 2019 16:12:55 +0200
parents ad434967a68c
children 0ce9b4f5fdf5
line wrap: on
line diff
--- a/Plugins/Engine/OrthancPlugins.cpp	Thu Jun 06 10:35:16 2019 +0200
+++ b/Plugins/Engine/OrthancPlugins.cpp	Thu Jun 06 16:12:55 2019 +0200
@@ -43,7 +43,6 @@
 #endif
 
 
-#include "../../Core/ChunkedBuffer.h"
 #include "../../Core/Compression/GzipCompressor.h"
 #include "../../Core/Compression/ZlibCompressor.h"
 #include "../../Core/DicomFormat/DicomArray.h"
@@ -356,7 +355,7 @@
       
     public:
       DicomWebBinaryFormatter(const _OrthancPluginEncodeDicomWeb& parameters) :
-        callback_(parameters.callback)
+      callback_(parameters.callback)
       {
       }
       
@@ -422,8 +421,8 @@
 
     public:
       PluginHttpOutput(HttpOutput& output) :
-        output_(output),
-        logDetails_(false)
+      output_(output),
+      logDetails_(false)
       {
       }
 
@@ -520,8 +519,8 @@
 
     public:
       ServerContextLock(PImpl& that) : 
-        lock_(that.contextMutex_),
-        context_(that.context_)
+      lock_(that.contextMutex_),
+      context_(that.context_)
       {
         if (context_ == NULL)
         {
@@ -976,15 +975,15 @@
 
 
 
-  class OrthancPlugins::HttpRequestBody : public HttpClient::IRequestChunkedBody
+  class OrthancPlugins::StreamingHttpRequest : public HttpClient::IRequestBody
   {
   private:
-    const _OrthancPluginHttpClientChunkedBody&  params_;
-    PluginsErrorDictionary&                     errorDictionary_;
+    const _OrthancPluginStreamingHttpClient&  params_;
+    PluginsErrorDictionary&                   errorDictionary_;
 
   public:
-    HttpRequestBody(const _OrthancPluginHttpClientChunkedBody& params,
-                       PluginsErrorDictionary&  errorDictionary) :
+    StreamingHttpRequest(const _OrthancPluginStreamingHttpClient& params,
+                         PluginsErrorDictionary&  errorDictionary) :
       params_(params),
       errorDictionary_(errorDictionary)
     {
@@ -992,23 +991,23 @@
 
     virtual bool ReadNextChunk(std::string& chunk)
     {
-      if (params_.requestBodyIsDone(params_.requestBody))
+      if (params_.requestIsDone(params_.request))
       {
         return false;
       }
       else
       {
-        size_t size = params_.requestBodyChunkSize(params_.requestBody);
+        size_t size = params_.requestChunkSize(params_.request);
 
         chunk.resize(size);
         
         if (size != 0)
         {
-          const void* data = params_.requestBodyChunkData(params_.requestBody);
+          const void* data = params_.requestChunkData(params_.request);
           memcpy(&chunk[0], data, size);
         }
 
-        OrthancPluginErrorCode error = params_.requestBodyNext(params_.requestBody);
+        OrthancPluginErrorCode error = params_.requestNext(params_.request);
         
         if (error != OrthancPluginErrorCode_Success)
         {
@@ -1024,6 +1023,46 @@
   };
 
 
+  class OrthancPlugins::StreamingHttpAnswer : public HttpClient::IAnswer
+  {
+  private:
+    const _OrthancPluginStreamingHttpClient&  params_;
+    PluginsErrorDictionary&                   errorDictionary_;
+
+  public:
+    StreamingHttpAnswer(const _OrthancPluginStreamingHttpClient& params,
+                        PluginsErrorDictionary&  errorDictionary) :
+      params_(params),
+      errorDictionary_(errorDictionary)
+    {
+    }
+
+    virtual void AddHeader(const std::string& key,
+                           const std::string& value)
+    {
+      OrthancPluginErrorCode error = params_.answerAddHeader(params_.answer, key.c_str(), value.c_str());
+        
+      if (error != OrthancPluginErrorCode_Success)
+      {
+        errorDictionary_.LogError(error, true);
+        throw OrthancException(static_cast<ErrorCode>(error));
+      }
+    }
+      
+    virtual void AddChunk(const void* data,
+                          size_t size)
+    {
+      OrthancPluginErrorCode error = params_.answerAddChunk(params_.answer, data, size);
+        
+      if (error != OrthancPluginErrorCode_Success)
+      {
+        errorDictionary_.LogError(error, true);
+        throw OrthancException(static_cast<ErrorCode>(error));
+      }
+    }
+  };
+
+
   OrthancPlugins::OrthancPlugins()
   {
     /* Sanity check of the compiler */
@@ -2085,8 +2124,8 @@
   }
 
 
-  static void RunHttpClient(HttpClient& client,
-                            const _OrthancPluginCallHttpClient2& parameters)
+  static void SetupHttpClient(HttpClient& client,
+                              const _OrthancPluginCallHttpClient2& parameters)
   {
     client.SetUrl(parameters.url);
     client.SetConvertHeadersToLowerCase(false);
@@ -2154,6 +2193,18 @@
       default:
         throw OrthancException(ErrorCode_ParameterOutOfRange);
     }
+  }
+
+
+  static void ExecuteHttpClientWithoutStream(uint16_t& httpStatus,
+                                             OrthancPluginMemoryBuffer* answerBody,
+                                             OrthancPluginMemoryBuffer* answerHeaders,
+                                             HttpClient& client)
+  {
+    if (answerBody == NULL)
+    {
+      throw OrthancException(ErrorCode_NullPointer);
+    }
 
     std::string body;
     HttpClient::HttpHeaders headers;
@@ -2161,7 +2212,7 @@
     bool success = client.Apply(body, headers);
 
     // The HTTP request has succeeded
-    *parameters.httpStatus = static_cast<uint16_t>(client.GetLastStatus());
+    httpStatus = static_cast<uint16_t>(client.GetLastStatus());
 
     if (!success)
     {
@@ -2169,7 +2220,7 @@
     }
 
     // Copy the HTTP headers of the answer, if the plugin requested them
-    if (parameters.answerHeaders != NULL)
+    if (answerHeaders != NULL)
     {
       Json::Value json = Json::objectValue;
 
@@ -2180,13 +2231,13 @@
       }
         
       std::string s = json.toStyledString();
-      CopyToMemoryBuffer(*parameters.answerHeaders, s);
+      CopyToMemoryBuffer(*answerHeaders, s);
     }
 
     // Copy the body of the answer if it makes sense
-    if (parameters.method != OrthancPluginHttpMethod_Delete)
+    if (client.GetMethod() != HttpMethod_Delete)
     {
-      CopyToMemoryBuffer(*parameters.answerBody, body);
+      CopyToMemoryBuffer(*answerBody, body);
     }
   }
 
@@ -2194,32 +2245,36 @@
   void OrthancPlugins::CallHttpClient(const void* parameters)
   {
     const _OrthancPluginCallHttpClient& p = *reinterpret_cast<const _OrthancPluginCallHttpClient*>(parameters);
-    
-    _OrthancPluginCallHttpClient2 converted;
-    memset(&converted, 0, sizeof(converted));
-
-    uint16_t httpStatus;
-
-    converted.answerBody = p.target;
-    converted.answerHeaders = NULL;
-    converted.httpStatus = &httpStatus;
-    converted.method = p.method;
-    converted.url = p.url;
-    converted.headersCount = 0;
-    converted.headersKeys = NULL;
-    converted.headersValues = NULL;
-    converted.body = p.body;
-    converted.bodySize = p.bodySize;
-    converted.username = p.username;
-    converted.password = p.password;
-    converted.timeout = 0;  // Use default timeout
-    converted.certificateFile = NULL;
-    converted.certificateKeyFile = NULL;
-    converted.certificateKeyPassword = NULL;
-    converted.pkcs11 = false;
 
     HttpClient client;
-    RunHttpClient(client, converted);
+
+    {    
+      _OrthancPluginCallHttpClient2 converted;
+      memset(&converted, 0, sizeof(converted));
+
+      converted.answerBody = NULL;
+      converted.answerHeaders = NULL;
+      converted.httpStatus = NULL;
+      converted.method = p.method;
+      converted.url = p.url;
+      converted.headersCount = 0;
+      converted.headersKeys = NULL;
+      converted.headersValues = NULL;
+      converted.body = p.body;
+      converted.bodySize = p.bodySize;
+      converted.username = p.username;
+      converted.password = p.password;
+      converted.timeout = 0;  // Use default timeout
+      converted.certificateFile = NULL;
+      converted.certificateKeyFile = NULL;
+      converted.certificateKeyPassword = NULL;
+      converted.pkcs11 = false;
+
+      SetupHttpClient(client, converted);
+    }
+
+    uint16_t status;
+    ExecuteHttpClientWithoutStream(status, p.target, NULL, client);
   }
 
 
@@ -2227,57 +2282,74 @@
   {
     const _OrthancPluginCallHttpClient2& p = *reinterpret_cast<const _OrthancPluginCallHttpClient2*>(parameters);
     
+    if (p.httpStatus == NULL)
+    {
+      throw OrthancException(ErrorCode_NullPointer);
+    }
+
     HttpClient client;
 
     if (p.method == OrthancPluginHttpMethod_Post ||
         p.method == OrthancPluginHttpMethod_Put)
     {
-        client.GetBody().assign(p.body, p.bodySize);
+      client.GetBody().assign(p.body, p.bodySize);
     }
     
-    RunHttpClient(client, p);
+    SetupHttpClient(client, p);
+    ExecuteHttpClientWithoutStream(*p.httpStatus, p.answerBody, p.answerHeaders, client);
   }
 
 
-  void OrthancPlugins::HttpClientChunkedBody(const void* parameters)
+  void OrthancPlugins::StreamingHttpClient(const void* parameters)
   {
-    const _OrthancPluginHttpClientChunkedBody& p =
-      *reinterpret_cast<const _OrthancPluginHttpClientChunkedBody*>(parameters);
-    
-    if (p.method != OrthancPluginHttpMethod_Post &&
-        p.method != OrthancPluginHttpMethod_Put)
+    const _OrthancPluginStreamingHttpClient& p =
+      *reinterpret_cast<const _OrthancPluginStreamingHttpClient*>(parameters);
+        
+    if (p.httpStatus == NULL)
     {
-      throw OrthancException(ErrorCode_ParameterOutOfRange,
-                             "This plugin service is only allowed for PUT and POST HTTP requests");
+      throw OrthancException(ErrorCode_NullPointer);
     }
 
-    HttpRequestBody body(p, pimpl_->dictionary_);
-
     HttpClient client;
-    client.SetBody(body);
+
+    {
+      _OrthancPluginCallHttpClient2 converted;
+      memset(&converted, 0, sizeof(converted));
+
+      converted.answerBody = NULL;
+      converted.answerHeaders = NULL;
+      converted.httpStatus = NULL;
+      converted.method = p.method;
+      converted.url = p.url;
+      converted.headersCount = p.headersCount;
+      converted.headersKeys = p.headersKeys;
+      converted.headersValues = p.headersValues;
+      converted.body = NULL;
+      converted.bodySize = 0;
+      converted.username = p.username;
+      converted.password = p.password;
+      converted.timeout = p.timeout;
+      converted.certificateFile = p.certificateFile;
+      converted.certificateKeyFile = p.certificateKeyFile;
+      converted.certificateKeyPassword = p.certificateKeyPassword;
+      converted.pkcs11 = p.pkcs11;
+
+      SetupHttpClient(client, converted);
+    }
     
-    _OrthancPluginCallHttpClient2 converted;
-    memset(&converted, 0, sizeof(converted));
-
-    converted.answerBody = p.answerBody;
-    converted.answerHeaders = p.answerHeaders;
-    converted.httpStatus = p.httpStatus;
-    converted.method = p.method;
-    converted.url = p.url;
-    converted.headersCount = p.headersCount;
-    converted.headersKeys = p.headersKeys;
-    converted.headersValues = p.headersValues;
-    converted.body = NULL;
-    converted.bodySize = 0;
-    converted.username = p.username;
-    converted.password = p.password;
-    converted.timeout = p.timeout;
-    converted.certificateFile = p.certificateFile;
-    converted.certificateKeyFile = p.certificateKeyFile;
-    converted.certificateKeyPassword = p.certificateKeyPassword;
-    converted.pkcs11 = p.pkcs11;
-    
-    RunHttpClient(client, converted);
+    StreamingHttpRequest body(p, pimpl_->dictionary_);
+    client.SetBody(body);
+
+    StreamingHttpAnswer answer(p, pimpl_->dictionary_);
+
+    bool success = client.Apply(answer);
+
+    *p.httpStatus = static_cast<uint16_t>(client.GetLastStatus());
+
+    if (!success)
+    {
+      HttpClient::ThrowException(client.GetLastStatus());
+    }
   }
 
 
@@ -2959,8 +3031,8 @@
         CallHttpClient2(parameters);
         return true;
 
-      case _OrthancPluginService_HttpClientChunkedBody:
-        HttpClientChunkedBody(parameters);
+      case _OrthancPluginService_StreamingHttpClient:
+        StreamingHttpClient(parameters);
         return true;
 
       case _OrthancPluginService_ConvertPixelFormat: