changeset 1606:31f4adefb88f

issuing HTTP requests from the plugin SDK
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 01 Sep 2015 17:37:26 +0200
parents fd0464ce1962
children a1c92fd4d26d
files Core/Enumerations.cpp Core/Enumerations.h Core/HttpClient.cpp Core/HttpClient.h Core/Lua/LuaContext.cpp OrthancServer/Scheduler/StorePeerCommand.cpp Plugins/Engine/OrthancPlugins.cpp Plugins/Engine/OrthancPlugins.h Plugins/Include/orthanc/OrthancCPlugin.h Resources/ErrorCodes.json
diffstat 10 files changed, 292 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/Core/Enumerations.cpp	Tue Sep 01 16:41:16 2015 +0200
+++ b/Core/Enumerations.cpp	Tue Sep 01 17:37:26 2015 +0200
@@ -136,6 +136,9 @@
       case ErrorCode_BadJson:
         return "Cannot parse a JSON document";
 
+      case ErrorCode_Unauthorized:
+        return "Bad credentials were provided to an HTTP request";
+
       case ErrorCode_SQLiteNotOpened:
         return "SQLite: The database is not opened";
 
@@ -1124,6 +1127,9 @@
       case ErrorCode_BadJson:
         return HttpStatus_400_BadRequest;
 
+      case ErrorCode_Unauthorized:
+        return HttpStatus_401_Unauthorized;
+
       default:
         return HttpStatus_500_InternalServerError;
     }
--- a/Core/Enumerations.h	Tue Sep 01 16:41:16 2015 +0200
+++ b/Core/Enumerations.h	Tue Sep 01 17:37:26 2015 +0200
@@ -75,6 +75,7 @@
     ErrorCode_UnknownPluginService = 26    /*!< Plugin invoking an unknown service */,
     ErrorCode_UnknownDicomTag = 27    /*!< Unknown DICOM tag */,
     ErrorCode_BadJson = 28    /*!< Cannot parse a JSON document */,
+    ErrorCode_Unauthorized = 29    /*!< Bad credentials were provided to an HTTP request */,
     ErrorCode_SQLiteNotOpened = 1000    /*!< SQLite: The database is not opened */,
     ErrorCode_SQLiteAlreadyOpened = 1001    /*!< SQLite: Connection is already open */,
     ErrorCode_SQLiteCannotOpen = 1002    /*!< SQLite: Unable to open the database */,
--- a/Core/HttpClient.cpp	Tue Sep 01 16:41:16 2015 +0200
+++ b/Core/HttpClient.cpp	Tue Sep 01 17:37:26 2015 +0200
@@ -84,6 +84,26 @@
   };
 
 
+  static void ThrowException(HttpStatus status)
+  {
+    switch (status)
+    {
+      case HttpStatus_400_BadRequest:
+        throw OrthancException(ErrorCode_BadRequest);
+
+      case HttpStatus_401_Unauthorized:
+        throw OrthancException(ErrorCode_Unauthorized);
+
+      case HttpStatus_404_NotFound:
+        throw OrthancException(ErrorCode_InexistentItem);
+
+      default:
+        throw OrthancException(ErrorCode_NetworkProtocol);
+    }
+  }
+
+
+
   static CURLcode CheckCode(CURLcode code)
   {
     if (code != CURLE_OK)
@@ -275,10 +295,10 @@
     if (method_ == HttpMethod_Post ||
         method_ == HttpMethod_Put)
     {
-      if (postData_.size() > 0)
+      if (body_.size() > 0)
       {
-        CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POSTFIELDS, postData_.c_str()));
-        CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POSTFIELDSIZE, postData_.size()));
+        CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POSTFIELDS, body_.c_str()));
+        CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POSTFIELDSIZE, body_.size()));
       }
       else
       {
@@ -392,4 +412,21 @@
     LOG(INFO) << "Setting the default timeout for HTTP client connections: " << timeout << " seconds";
     globalTimeout_ = timeout;
   }
+
+
+  void HttpClient::ApplyAndThrowException(std::string& answer)
+  {
+    if (!Apply(answer))
+    {
+      ThrowException(GetLastStatus());
+    }
+  }
+  
+  void HttpClient::ApplyAndThrowException(Json::Value& answer)
+  {
+    if (!Apply(answer))
+    {
+      ThrowException(GetLastStatus());
+    }
+  }
 }
--- a/Core/HttpClient.h	Tue Sep 01 16:41:16 2015 +0200
+++ b/Core/HttpClient.h	Tue Sep 01 17:37:26 2015 +0200
@@ -50,7 +50,7 @@
     std::string credentials_;
     HttpMethod method_;
     HttpStatus lastStatus_;
-    std::string postData_;
+    std::string body_;  // This only makes sense for POST and PUT requests
     bool isVerbose_;
     long timeout_;
     std::string proxy_;
@@ -103,19 +103,19 @@
       return timeout_;
     }
 
-    void SetPostData(const std::string& data)
+    void SetBody(const std::string& data)
     {
-      postData_ = data;
+      body_ = data;
     }
 
-    std::string& AccessPostData()
+    std::string& GetBody()
     {
-      return postData_;
+      return body_;
     }
 
-    const std::string& AccessPostData() const
+    const std::string& GetBody() const
     {
-      return postData_;
+      return body_;
     }
 
     void SetVerbose(bool isVerbose);
@@ -165,5 +165,9 @@
     static void GlobalFinalize();
 
     static void SetDefaultTimeout(long timeout);
+
+    void ApplyAndThrowException(std::string& answer);
+
+    void ApplyAndThrowException(Json::Value& answer);
   };
 }
--- a/Core/Lua/LuaContext.cpp	Tue Sep 01 16:41:16 2015 +0200
+++ b/Core/Lua/LuaContext.cpp	Tue Sep 01 17:37:26 2015 +0200
@@ -241,11 +241,11 @@
 
     if (nArgs >= 2)
     {
-      that.httpClient_.SetPostData(lua_tostring(state, 2));
+      that.httpClient_.SetBody(lua_tostring(state, 2));
     }
     else
     {
-      that.httpClient_.AccessPostData().clear();
+      that.httpClient_.GetBody().clear();
     }
 
     // Do the HTTP POST/PUT request
--- a/OrthancServer/Scheduler/StorePeerCommand.cpp	Tue Sep 01 16:41:16 2015 +0200
+++ b/OrthancServer/Scheduler/StorePeerCommand.cpp	Tue Sep 01 17:37:26 2015 +0200
@@ -70,7 +70,7 @@
 
       try
       {
-        context_.ReadFile(client.AccessPostData(), *it, FileContentType_Dicom);
+        context_.ReadFile(client.GetBody(), *it, FileContentType_Dicom);
 
         std::string answer;
         if (!client.Apply(answer))
--- a/Plugins/Engine/OrthancPlugins.cpp	Tue Sep 01 16:41:16 2015 +0200
+++ b/Plugins/Engine/OrthancPlugins.cpp	Tue Sep 01 17:37:26 2015 +0200
@@ -1121,6 +1121,53 @@
   }
 
 
+  void OrthancPlugins::CallHttpClient(const void* parameters)
+  {
+    const _OrthancPluginCallHttpClient& p = *reinterpret_cast<const _OrthancPluginCallHttpClient*>(parameters);
+
+    HttpClient client;
+    client.SetUrl(p.url);
+
+    if (p.username != NULL && 
+        p.password != NULL)
+    {
+      client.SetCredentials(p.username, p.password);
+    }
+
+    switch (p.method)
+    {
+      case OrthancPluginHttpMethod_Get:
+        client.SetMethod(HttpMethod_Get);
+        break;
+
+      case OrthancPluginHttpMethod_Post:
+        client.SetMethod(HttpMethod_Post);
+        client.GetBody().assign(p.body, p.bodySize);
+        break;
+
+      case OrthancPluginHttpMethod_Put:
+        client.SetMethod(HttpMethod_Put);
+        client.GetBody().assign(p.body, p.bodySize);
+        break;
+
+      case OrthancPluginHttpMethod_Delete:
+        client.SetMethod(HttpMethod_Delete);
+        break;
+
+      default:
+        throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+
+    std::string s;
+    client.ApplyAndThrowException(s);
+
+    if (p.method != OrthancPluginHttpMethod_Delete)
+    {
+      CopyToMemoryBuffer(*p.target, s);
+    }
+  }
+
+
   bool OrthancPlugins::InvokeService(_OrthancPluginService service,
                                      const void* parameters)
   {
@@ -1479,6 +1526,10 @@
         CompressImage(parameters);
         return true;
 
+      case _OrthancPluginService_CallHttpClient:
+        CallHttpClient(parameters);
+        return true;
+
       default:
       {
         // This service is unknown to the Orthanc plugin engine
--- a/Plugins/Engine/OrthancPlugins.h	Tue Sep 01 16:41:16 2015 +0200
+++ b/Plugins/Engine/OrthancPlugins.h	Tue Sep 01 17:37:26 2015 +0200
@@ -104,6 +104,8 @@
 
     void CompressImage(const void* parameters);
 
+    void CallHttpClient(const void* parameters);
+
   public:
     OrthancPlugins();
 
--- a/Plugins/Include/orthanc/OrthancCPlugin.h	Tue Sep 01 16:41:16 2015 +0200
+++ b/Plugins/Include/orthanc/OrthancCPlugin.h	Tue Sep 01 17:37:26 2015 +0200
@@ -208,6 +208,7 @@
     OrthancPluginErrorCode_UnknownPluginService = 26    /*!< Plugin invoking an unknown service */,
     OrthancPluginErrorCode_UnknownDicomTag = 27    /*!< Unknown DICOM tag */,
     OrthancPluginErrorCode_BadJson = 28    /*!< Cannot parse a JSON document */,
+    OrthancPluginErrorCode_Unauthorized = 29    /*!< Bad credentials were provided to an HTTP request */,
     OrthancPluginErrorCode_SQLiteNotOpened = 1000    /*!< SQLite: The database is not opened */,
     OrthancPluginErrorCode_SQLiteAlreadyOpened = 1001    /*!< SQLite: Connection is already open */,
     OrthancPluginErrorCode_SQLiteCannotOpen = 1002    /*!< SQLite: Unable to open the database */,
@@ -375,6 +376,7 @@
     _OrthancPluginService_ReadFile = 15,
     _OrthancPluginService_WriteFile = 16,
     _OrthancPluginService_GetErrorDescription = 17,
+    _OrthancPluginService_CallHttpClient = 18,
 
     /* Registration of callbacks */
     _OrthancPluginService_RegisterRestCallback = 1000,
@@ -1154,6 +1156,7 @@
    * @param target The target memory buffer.
    * @param uri The URI in the built-in Orthanc API.
    * @return 0 if success, or the error code if failure.
+   * @see OrthancPluginRestApiGetAfterPlugins
    * @ingroup Orthanc
    **/
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode  OrthancPluginRestApiGet(
@@ -1182,6 +1185,7 @@
    * @param target The target memory buffer.
    * @param uri The URI in the built-in Orthanc API.
    * @return 0 if success, or the error code if failure.
+   * @see OrthancPluginRestApiGet
    * @ingroup Orthanc
    **/
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode  OrthancPluginRestApiGetAfterPlugins(
@@ -1217,6 +1221,7 @@
    * @param body The body of the POST request.
    * @param bodySize The size of the body.
    * @return 0 if success, or the error code if failure.
+   * @see OrthancPluginRestApiPostAfterPlugins
    * @ingroup Orthanc
    **/
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode  OrthancPluginRestApiPost(
@@ -1250,6 +1255,7 @@
    * @param body The body of the POST request.
    * @param bodySize The size of the body.
    * @return 0 if success, or the error code if failure.
+   * @see OrthancPluginRestApiPost
    * @ingroup Orthanc
    **/
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode  OrthancPluginRestApiPostAfterPlugins(
@@ -1277,6 +1283,7 @@
    * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
    * @param uri The URI to delete in the built-in Orthanc API.
    * @return 0 if success, or the error code if failure.
+   * @see OrthancPluginRestApiDeleteAfterPlugins
    * @ingroup Orthanc
    **/
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode  OrthancPluginRestApiDelete(
@@ -1298,6 +1305,7 @@
    * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
    * @param uri The URI to delete in the built-in Orthanc API.
    * @return 0 if success, or the error code if failure.
+   * @see OrthancPluginRestApiDelete
    * @ingroup Orthanc
    **/
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode  OrthancPluginRestApiDeleteAfterPlugins(
@@ -1321,6 +1329,7 @@
    * @param body The body of the PUT request.
    * @param bodySize The size of the body.
    * @return 0 if success, or the error code if failure.
+   * @see OrthancPluginRestApiPutAfterPlugins
    * @ingroup Orthanc
    **/
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode  OrthancPluginRestApiPut(
@@ -1355,6 +1364,7 @@
    * @param body The body of the PUT request.
    * @param bodySize The size of the body.
    * @return 0 if success, or the error code if failure.
+   * @see OrthancPluginRestApiPut
    * @ingroup Orthanc
    **/
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode  OrthancPluginRestApiPutAfterPlugins(
@@ -3100,6 +3110,168 @@
 
 
 
+
+  typedef struct
+  {
+    OrthancPluginMemoryBuffer*  target;
+    OrthancPluginHttpMethod     method;
+    const char*                 url;
+    const char*                 username;
+    const char*                 password;
+    const char*                 body;
+    uint32_t                    bodySize;
+  } _OrthancPluginCallHttpClient;
+
+
+  /**
+   * @brief Issue a HTTP GET call.
+   * 
+   * Make a HTTP GET call to the given URL. The result to the query is
+   * stored into a newly allocated memory buffer. Favor
+   * OrthancPluginRestApiGet() if calling the built-in REST API of the
+   * Orthanc instance that hosts this plugin.
+   * 
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param target The target memory buffer.
+   * @param url The URL of interest.
+   * @param username The username (can be <tt>NULL</tt> if no password protection).
+   * @param password The password (can be <tt>NULL</tt> if no password protection).
+   * @return 0 if success, or the error code if failure.
+   **/
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode  OrthancPluginHttpGet(
+    OrthancPluginContext*       context,
+    OrthancPluginMemoryBuffer*  target,
+    const char*                 url,
+    const char*                 username,
+    const char*                 password)
+  {
+    _OrthancPluginCallHttpClient params;
+    memset(&params, 0, sizeof(params));
+
+    params.target = target;
+    params.method = OrthancPluginHttpMethod_Get;
+    params.url = url;
+    params.username = username;
+    params.password = password;
+
+    return context->InvokeService(context, _OrthancPluginService_CallHttpClient, &params);
+  }
+
+
+  /**
+   * @brief Issue a HTTP POST call.
+   * 
+   * Make a HTTP POST call to the given URL. The result to the query
+   * is stored into a newly allocated memory buffer. Favor
+   * OrthancPluginRestApiPost() if calling the built-in REST API of
+   * the Orthanc instance that hosts this plugin.
+   * 
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param target The target memory buffer.
+   * @param url The URL of interest.
+   * @param body The content of the body of the request.
+   * @param bodySize The size of the body of the request.
+   * @param username The username (can be <tt>NULL</tt> if no password protection).
+   * @param password The password (can be <tt>NULL</tt> if no password protection).
+   * @return 0 if success, or the error code if failure.
+   **/
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode  OrthancPluginHttpPost(
+    OrthancPluginContext*       context,
+    OrthancPluginMemoryBuffer*  target,
+    const char*                 url,
+    const char*                 body,
+    uint32_t                    bodySize,
+    const char*                 username,
+    const char*                 password)
+  {
+    _OrthancPluginCallHttpClient params;
+    memset(&params, 0, sizeof(params));
+
+    params.target = target;
+    params.method = OrthancPluginHttpMethod_Post;
+    params.url = url;
+    params.body = body;
+    params.bodySize = bodySize;
+    params.username = username;
+    params.password = password;
+
+    return context->InvokeService(context, _OrthancPluginService_CallHttpClient, &params);
+  }
+
+
+  /**
+   * @brief Issue a HTTP PUT call.
+   * 
+   * Make a HTTP PUT call to the given URL. The result to the query is
+   * stored into a newly allocated memory buffer. Favor
+   * OrthancPluginRestApiPut() if calling the built-in REST API of the
+   * Orthanc instance that hosts this plugin.
+   * 
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param target The target memory buffer.
+   * @param url The URL of interest.
+   * @param body The content of the body of the request.
+   * @param bodySize The size of the body of the request.
+   * @param username The username (can be <tt>NULL</tt> if no password protection).
+   * @param password The password (can be <tt>NULL</tt> if no password protection).
+   * @return 0 if success, or the error code if failure.
+   **/
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode  OrthancPluginHttpPut(
+    OrthancPluginContext*       context,
+    OrthancPluginMemoryBuffer*  target,
+    const char*                 url,
+    const char*                 body,
+    uint32_t                    bodySize,
+    const char*                 username,
+    const char*                 password)
+  {
+    _OrthancPluginCallHttpClient params;
+    memset(&params, 0, sizeof(params));
+
+    params.target = target;
+    params.method = OrthancPluginHttpMethod_Put;
+    params.url = url;
+    params.body = body;
+    params.bodySize = bodySize;
+    params.username = username;
+    params.password = password;
+
+    return context->InvokeService(context, _OrthancPluginService_CallHttpClient, &params);
+  }
+
+
+  /**
+   * @brief Issue a HTTP DELETE call.
+   * 
+   * Make a HTTP DELETE call to the given URL. Favor
+   * OrthancPluginRestApiDelete() if calling the built-in REST API of
+   * the Orthanc instance that hosts this plugin.
+   * 
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param url The URL of interest.
+   * @param username The username (can be <tt>NULL</tt> if no password protection).
+   * @param password The password (can be <tt>NULL</tt> if no password protection).
+   * @return 0 if success, or the error code if failure.
+   **/
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode  OrthancPluginHttpDelete(
+    OrthancPluginContext*       context,
+    const char*                 url,
+    const char*                 username,
+    const char*                 password)
+  {
+    _OrthancPluginCallHttpClient params;
+    memset(&params, 0, sizeof(params));
+
+    params.method = OrthancPluginHttpMethod_Delete;
+    params.url = url;
+    params.username = username;
+    params.password = password;
+
+    return context->InvokeService(context, _OrthancPluginService_CallHttpClient, &params);
+  }
+
+
+
 #ifdef  __cplusplus
 }
 #endif
--- a/Resources/ErrorCodes.json	Tue Sep 01 16:41:16 2015 +0200
+++ b/Resources/ErrorCodes.json	Tue Sep 01 17:37:26 2015 +0200
@@ -163,6 +163,12 @@
     "HttpStatus": 400, 
     "Name": "BadJson", 
     "Description": "Cannot parse a JSON document"
+  }, 
+  {
+    "Code": 29, 
+    "HttpStatus": 401, 
+    "Name": "Unauthorized", 
+    "Description": "Bad credentials were provided to an HTTP request"
   },