diff Plugins/Samples/Common/OrthancPluginCppWrapper.cpp @ 3387:a48d652f1500

new function OrthancPluginHttpClientChunkedBody(), new class OrthancPlugins::HttpClient
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 05 Jun 2019 17:17:48 +0200
parents 0f721f015b85
children 18cd4951fccc
line wrap: on
line diff
--- a/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp	Wed Jun 05 14:40:14 2019 +0200
+++ b/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp	Wed Jun 05 17:17:48 2019 +0200
@@ -440,9 +440,9 @@
                   const std::string& password)
   {
     OrthancPluginErrorCode error = OrthancPluginHttpDelete
-        (GetGlobalContext(), url.c_str(),
-         username.empty() ? NULL : username.c_str(),
-         password.empty() ? NULL : password.c_str());
+      (GetGlobalContext(), url.c_str(),
+       username.empty() ? NULL : username.c_str(),
+       password.empty() ? NULL : password.c_str());
 
     if (error == OrthancPluginErrorCode_Success)
     {
@@ -591,19 +591,19 @@
 
     switch (configuration_[key].type())
     {
-    case Json::intValue:
-      target = configuration_[key].asInt();
-      return true;
+      case Json::intValue:
+        target = configuration_[key].asInt();
+        return true;
 
-    case Json::uintValue:
-      target = configuration_[key].asUInt();
-      return true;
+      case Json::uintValue:
+        target = configuration_[key].asUInt();
+        return true;
 
-    default:
-      LogError("The configuration option \"" + GetPath(key) +
-               "\" is not an integer as expected");
+      default:
+        LogError("The configuration option \"" + GetPath(key) +
+                 "\" is not an integer as expected");
 
-      ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat);
+        ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat);
     }
   }
 
@@ -667,23 +667,23 @@
 
     switch (configuration_[key].type())
     {
-    case Json::realValue:
-      target = configuration_[key].asFloat();
-      return true;
+      case Json::realValue:
+        target = configuration_[key].asFloat();
+        return true;
 
-    case Json::intValue:
-      target = static_cast<float>(configuration_[key].asInt());
-      return true;
+      case Json::intValue:
+        target = static_cast<float>(configuration_[key].asInt());
+        return true;
 
-    case Json::uintValue:
-      target = static_cast<float>(configuration_[key].asUInt());
-      return true;
+      case Json::uintValue:
+        target = static_cast<float>(configuration_[key].asUInt());
+        return true;
 
-    default:
-      LogError("The configuration option \"" + GetPath(key) +
-               "\" is not an integer as expected");
+      default:
+        LogError("The configuration option \"" + GetPath(key) +
+                 "\" is not an integer as expected");
 
-      ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat);
+        ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat);
     }
   }
 
@@ -703,41 +703,41 @@
 
     switch (configuration_[key].type())
     {
-    case Json::arrayValue:
-    {
-      bool ok = true;
-
-      for (Json::Value::ArrayIndex i = 0; ok && i < configuration_[key].size(); i++)
+      case Json::arrayValue:
       {
-        if (configuration_[key][i].type() == Json::stringValue)
+        bool ok = true;
+
+        for (Json::Value::ArrayIndex i = 0; ok && i < configuration_[key].size(); i++)
         {
-          target.push_back(configuration_[key][i].asString());
+          if (configuration_[key][i].type() == Json::stringValue)
+          {
+            target.push_back(configuration_[key][i].asString());
+          }
+          else
+          {
+            ok = false;
+          }
         }
-        else
+
+        if (ok)
         {
-          ok = false;
+          return true;
         }
+
+        break;
       }
 
-      if (ok)
-      {
-        return true;
-      }
-
-      break;
-    }
+      case Json::stringValue:
+        if (allowSingleString)
+        {
+          target.push_back(configuration_[key].asString());
+          return true;
+        }
 
-    case Json::stringValue:
-      if (allowSingleString)
-      {
-        target.push_back(configuration_[key].asString());
-        return true;
-      }
+        break;
 
-      break;
-
-    default:
-      break;
+      default:
+        break;
     }
 
     LogError("The configuration option \"" + GetPath(key) +
@@ -758,7 +758,7 @@
       target.clear();
 
       for (std::list<std::string>::const_iterator
-           it = lst.begin(); it != lst.end(); ++it)
+             it = lst.begin(); it != lst.end(); ++it)
       {
         target.insert(*it);
       }
@@ -941,7 +941,7 @@
                              void*                     buffer)
   {
     image_ = OrthancPluginCreateImageAccessor
-        (GetGlobalContext(), format, width, height, pitch, buffer);
+      (GetGlobalContext(), format, width, height, pitch, buffer);
 
     if (image_ == NULL)
     {
@@ -1143,7 +1143,7 @@
 
   void AnswerJson(const Json::Value& value,
                   OrthancPluginRestOutput* output
-                  )
+    )
   {
     Json::StyledWriter writer;
     std::string bodyString = writer.write(value);
@@ -1154,7 +1154,7 @@
   void AnswerString(const std::string& answer,
                     const char* mimeType,
                     OrthancPluginRestOutput* output
-                    )
+    )
   {
     OrthancPluginAnswerBuffer(GetGlobalContext(), output, answer.c_str(), answer.size(), mimeType);
   }
@@ -1354,15 +1354,15 @@
     // Parse the version of the Orthanc core
     int aa, bb, cc;
     if (
-    #ifdef _MSC_VER
-        sscanf_s
-    #else
-        sscanf
-    #endif
-        (GetGlobalContext()->orthancVersion, "%4d.%4d.%4d", &aa, &bb, &cc) != 3 ||
-        aa < 0 ||
-        bb < 0 ||
-        cc < 0)
+#ifdef _MSC_VER
+      sscanf_s
+#else
+      sscanf
+#endif
+      (GetGlobalContext()->orthancVersion, "%4d.%4d.%4d", &aa, &bb, &cc) != 3 ||
+      aa < 0 ||
+      bb < 0 ||
+      cc < 0)
     {
       return false;
     }
@@ -1590,9 +1590,9 @@
     OrthancPlugins::MemoryBuffer answer;
     uint16_t status;
     OrthancPluginErrorCode code = OrthancPluginCallPeerApi
-        (GetGlobalContext(), *answer, NULL, &status, peers_,
-         static_cast<uint32_t>(index), OrthancPluginHttpMethod_Get, uri.c_str(),
-         0, NULL, NULL, NULL, 0, timeout_);
+      (GetGlobalContext(), *answer, NULL, &status, peers_,
+       static_cast<uint32_t>(index), OrthancPluginHttpMethod_Get, uri.c_str(),
+       0, NULL, NULL, NULL, 0, timeout_);
 
     if (code == OrthancPluginErrorCode_Success)
     {
@@ -1714,9 +1714,9 @@
     OrthancPlugins::MemoryBuffer answer;
     uint16_t status;
     OrthancPluginErrorCode code = OrthancPluginCallPeerApi
-        (GetGlobalContext(), *answer, NULL, &status, peers_,
-         static_cast<uint32_t>(index), OrthancPluginHttpMethod_Post, uri.c_str(),
-         0, NULL, NULL, body.empty() ? NULL : body.c_str(), body.size(), timeout_);
+      (GetGlobalContext(), *answer, NULL, &status, peers_,
+       static_cast<uint32_t>(index), OrthancPluginHttpMethod_Post, uri.c_str(),
+       0, NULL, NULL, body.empty() ? NULL : body.c_str(), body.size(), timeout_);
 
     if (code == OrthancPluginErrorCode_Success)
     {
@@ -1742,9 +1742,9 @@
     OrthancPlugins::MemoryBuffer answer;
     uint16_t status;
     OrthancPluginErrorCode code = OrthancPluginCallPeerApi
-        (GetGlobalContext(), *answer, NULL, &status, peers_,
-         static_cast<uint32_t>(index), OrthancPluginHttpMethod_Put, uri.c_str(),
-         0, NULL, NULL, body.empty() ? NULL : body.c_str(), body.size(), timeout_);
+      (GetGlobalContext(), *answer, NULL, &status, peers_,
+       static_cast<uint32_t>(index), OrthancPluginHttpMethod_Put, uri.c_str(),
+       0, NULL, NULL, body.empty() ? NULL : body.c_str(), body.size(), timeout_);
 
     if (code == OrthancPluginErrorCode_Success)
     {
@@ -2000,9 +2000,9 @@
     }
 
     OrthancPluginJob* orthanc = OrthancPluginCreateJob(
-          GetGlobalContext(), job, CallbackFinalize, job->jobType_.c_str(),
-          CallbackGetProgress, CallbackGetContent, CallbackGetSerialized,
-          CallbackStep, CallbackStop, CallbackReset);
+      GetGlobalContext(), job, CallbackFinalize, job->jobType_.c_str(),
+      CallbackGetProgress, CallbackGetContent, CallbackGetSerialized,
+      CallbackStep, CallbackStop, CallbackReset);
 
     if (orthanc == NULL)
     {
@@ -2055,4 +2055,220 @@
                                  OrthancPluginMetricsType_Timer);
   }
 #endif
+
+
+
+#if HAS_ORTHANC_PLUGIN_HTTP_CHUNKED_BODY == 1
+  class HttpClient::ChunkedBody : public boost::noncopyable
+  {
+  private:
+    static ChunkedBody& GetObject(void* body)
+    {
+      assert(body != NULL);
+      return *reinterpret_cast<ChunkedBody*>(body);
+    }
+
+    IChunkedBody&  body_;
+    bool           done_;
+    std::string    chunk_;
+
+  public:
+    ChunkedBody(IChunkedBody& body) :
+      body_(body),
+      done_(false)
+    {
+    }      
+
+    static uint8_t IsDone(void* body)
+    {
+      return GetObject(body).done_;
+    }
+    
+    static const void* GetChunkData(void* body)
+    {
+      return GetObject(body).chunk_.c_str();
+    }
+    
+    static uint32_t GetChunkSize(void* body)
+    {
+      return static_cast<uint32_t>(GetObject(body).chunk_.size());
+    }
+
+    static OrthancPluginErrorCode Next(void* body)
+    {
+      ChunkedBody& that = GetObject(body);
+        
+      if (that.done_)
+      {
+        return OrthancPluginErrorCode_BadSequenceOfCalls;
+      }
+      else
+      {
+        try
+        {
+          that.done_ = !that.body_.ReadNextChunk(that.chunk_);
+          return OrthancPluginErrorCode_Success;
+        }
+        catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e)
+        {
+          return static_cast<OrthancPluginErrorCode>(e.GetErrorCode());
+        }
+        catch (...)
+        {
+          return OrthancPluginErrorCode_InternalError;
+        }
+      }
+    }    
+  };
+#endif
+
+  HttpClient::HttpClient() :
+    httpStatus_(0),
+    method_(OrthancPluginHttpMethod_Get),
+    timeout_(0),
+    pkcs11_(false),
+    chunkedBody_(NULL)
+  {
+  }
+
+  
+  void HttpClient::SetCredentials(const std::string& username,
+                                  const std::string& password)
+  {
+    username_ = username;
+    password_ = password;
+  }
+
+  
+  void HttpClient::ClearCredentials()
+  {
+    username_.empty();
+    password_.empty();
+  }
+
+
+  void HttpClient::SetCertificate(const std::string& certificateFile,
+                                  const std::string& keyFile,
+                                  const std::string& keyPassword)
+  {
+    certificateFile_ = certificateFile;
+    certificateKeyFile_ = keyFile;
+    certificateKeyPassword_ = keyPassword;
+  }
+
+  
+  void HttpClient::ClearCertificate()
+  {
+    certificateFile_.clear();
+    certificateKeyFile_.clear();
+    certificateKeyPassword_.clear();
+  }
+
+
+  void HttpClient::ClearBody()
+  {
+    body_.clear();
+    chunkedBody_ = NULL;
+  }
+
+  
+  void HttpClient::SwapBody(std::string& body)
+  {
+    body_.swap(body);
+    chunkedBody_ = NULL;
+  }
+
+  
+  void HttpClient::SetBody(const std::string& body)
+  {
+    body_ = body;
+    chunkedBody_ = NULL;
+  }
+
+  
+#if HAS_ORTHANC_PLUGIN_HTTP_CHUNKED_BODY == 1
+  void HttpClient::SetBody(IChunkedBody& body)
+  {
+    body_.clear();
+    chunkedBody_ = &body;
+  }
+#endif
+
+  
+  void HttpClient::Execute()
+  {
+    std::vector<const char*> headersKeys;
+    std::vector<const char*> headersValues;
+
+    headersKeys.reserve(headers_.size());
+    headersValues.reserve(headers_.size());
+
+    for (HttpHeaders::const_iterator it = headers_.begin();
+         it != headers_.end(); ++it)
+    {
+      headersKeys.push_back(it->first.c_str());
+      headersValues.push_back(it->second.c_str());
+    }
+
+    OrthancPluginErrorCode error;
+      
+    if (chunkedBody_ == NULL)
+    {
+      error = OrthancPluginHttpClient(
+        GetGlobalContext(),
+        *answerBody_,
+        *answerHeaders_,
+        &httpStatus_,
+        method_,
+        url_.c_str(),
+        headersKeys.size(),
+        headersKeys.empty() ? NULL : &headersKeys[0],
+        headersValues.empty() ? NULL : &headersValues[0],
+        body_.empty() ? NULL : body_.c_str(),
+        body_.size(),
+        username_.empty() ? NULL : username_.c_str(),
+        password_.empty() ? NULL : password_.c_str(),
+        timeout_,
+        certificateFile_.empty() ? NULL : certificateFile_.c_str(),
+        certificateFile_.empty() ? NULL : certificateKeyFile_.c_str(),
+        certificateFile_.empty() ? NULL : certificateKeyPassword_.c_str(),
+        pkcs11_ ? 1 : 0);
+    }
+    else
+    {
+#if HAS_ORTHANC_PLUGIN_HTTP_CHUNKED_BODY != 1
+      error = OrthancPluginErrorCode_InternalError;
+#else
+      ChunkedBody wrapper(*chunkedBody_);
+        
+      error = OrthancPluginHttpClientChunkedBody(
+        GetGlobalContext(),
+        *answerBody_,
+        *answerHeaders_,
+        &httpStatus_,
+        method_,
+        url_.c_str(),
+        headersKeys.size(),
+        headersKeys.empty() ? NULL : &headersKeys[0],
+        headersValues.empty() ? NULL : &headersValues[0],
+        username_.empty() ? NULL : username_.c_str(),
+        password_.empty() ? NULL : password_.c_str(),
+        timeout_,
+        certificateFile_.empty() ? NULL : certificateFile_.c_str(),
+        certificateFile_.empty() ? NULL : certificateKeyFile_.c_str(),
+        certificateFile_.empty() ? NULL : certificateKeyPassword_.c_str(),
+        pkcs11_ ? 1 : 0,
+        &wrapper,
+        ChunkedBody::IsDone,
+        ChunkedBody::GetChunkData,
+        ChunkedBody::GetChunkSize,
+        ChunkedBody::Next);
+#endif
+    }
+
+    if (error != OrthancPluginErrorCode_Success)
+    {
+      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(error);
+    }
+  }
 }