changeset 1052:cc4ff680e2a0

http requests in lua
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 23 Jul 2014 15:08:09 +0200
parents 92f4bf2c5d73
children ee5cbe6e48d3
files Core/HttpClient.cpp Core/HttpClient.h Core/Lua/LuaContext.cpp Core/Lua/LuaContext.h UnitTestsSources/LuaTests.cpp
diffstat 5 files changed, 201 insertions(+), 47 deletions(-) [+]
line wrap: on
line diff
--- a/Core/HttpClient.cpp	Wed Jul 23 12:59:28 2014 +0200
+++ b/Core/HttpClient.cpp	Wed Jul 23 15:08:09 2014 +0200
@@ -161,7 +161,15 @@
     answer.clear();
     CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_URL, url_.c_str()));
     CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_WRITEDATA, &answer));
+
+    // Reset the parameters from previous calls to Apply()
     CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_HTTPHEADER, NULL));
+    CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_HTTPGET, 0L));
+    CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POST, 0L));
+    CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_NOBODY, 0L));
+    CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_CUSTOMREQUEST, NULL));
+    CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POSTFIELDS, NULL));
+    CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POSTFIELDSIZE, 0));
 
     if (credentials_.size() != 0)
     {
@@ -177,7 +185,31 @@
     case HttpMethod_Post:
       CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POST, 1L));
       CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_HTTPHEADER, pimpl_->postHeaders_));
+      break;
 
+    case HttpMethod_Delete:
+      CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_NOBODY, 1L));
+      CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_CUSTOMREQUEST, "DELETE"));
+      break;
+
+    case HttpMethod_Put:
+      // http://stackoverflow.com/a/7570281/881731: Don't use
+      // CURLOPT_PUT if there is a body
+
+      // CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_PUT, 1L));
+
+      curl_easy_setopt(pimpl_->curl_, CURLOPT_CUSTOMREQUEST, "PUT"); /* !!! */
+      CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_HTTPHEADER, pimpl_->postHeaders_));      
+      break;
+
+    default:
+      throw OrthancException(ErrorCode_InternalError);
+    }
+
+
+    if (method_ == HttpMethod_Post ||
+        method_ == HttpMethod_Put)
+    {
       if (postData_.size() > 0)
       {
         CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POSTFIELDS, postData_.c_str()));
@@ -188,21 +220,8 @@
         CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POSTFIELDS, NULL));
         CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POSTFIELDSIZE, 0));
       }
-
-      break;
-
-    case HttpMethod_Delete:
-      CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_NOBODY, 1L));
-      CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_CUSTOMREQUEST, "DELETE"));
-      break;
+    }
 
-    case HttpMethod_Put:
-      CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_PUT, 1L));
-      break;
-
-    default:
-      throw OrthancException(ErrorCode_InternalError);
-    }
 
     // Do the actual request
     CheckCode(curl_easy_perform(pimpl_->curl_));
--- a/Core/HttpClient.h	Wed Jul 23 12:59:28 2014 +0200
+++ b/Core/HttpClient.h	Wed Jul 23 15:08:09 2014 +0200
@@ -89,6 +89,11 @@
       return method_;
     }
 
+    void SetPostData(const std::string& data)
+    {
+      postData_ = data;
+    }
+
     std::string& AccessPostData()
     {
       return postData_;
--- a/Core/Lua/LuaContext.cpp	Wed Jul 23 12:59:28 2014 +0200
+++ b/Core/Lua/LuaContext.cpp	Wed Jul 23 15:08:09 2014 +0200
@@ -93,30 +93,10 @@
     return 0;
   }
 
-  
-  int LuaContext::CallHttpGet(lua_State *state)
+
+  bool LuaContext::DoHttpQuery(lua_State* state,
+                               bool isJson)
   {
-    LuaContext& that = GetLuaContext(state);
-
-    // Check that there is 1 string argument
-    int nArgs = lua_gettop(state);
-    if ((nArgs != 1 && nArgs != 2) ||
-        !lua_isstring(state, 1) ||
-        (nArgs == 2 && !lua_isboolean(state, 2)))
-    {
-      LOG(ERROR) << "Lua: Bad URL in HttpGet";
-
-      lua_pushstring(state, "ERROR");
-      return 1;
-    }
-
-    // Configure the HTTP client class
-    const char* url = lua_tostring(state, 1);
-    bool isJson = (nArgs == 2 && lua_toboolean(state, 2));
-    that.httpClient_.SetMethod(HttpMethod_Get);
-    that.httpClient_.SetUrl(url);
-
-    // Do the HTTP GET request
     std::string str;
     Json::Value json;
 
@@ -124,29 +104,147 @@
     {
       if (isJson)
       {
-        that.httpClient_.Apply(json);
+        httpClient_.Apply(json);
       }
       else
       {
-        that.httpClient_.Apply(str);
+        httpClient_.Apply(str);
       }
     }
     catch (OrthancException& e)
     {
-      LOG(ERROR) << "Lua: Error in HttpGet for URL " << url << ": " << e.What();
-      
+      return false;
+    }
+
+    // Return the result of the HTTP request
+    if (isJson)
+    {
+      PushJson(json);
+    }
+    else
+    {
+      lua_pushstring(state, str.c_str());
+    }
+
+    return true;
+  }
+
+  
+  int LuaContext::CallHttpGet(lua_State *state)
+  {
+    LuaContext& that = GetLuaContext(state);
+
+    // Check the types of the arguments
+    int nArgs = lua_gettop(state);
+    if ((nArgs != 1 && nArgs != 2) ||
+        !lua_isstring(state, 1) ||                 // URL
+        (nArgs >= 2 && !lua_isboolean(state, 2)))  // Interpret result as JSON
+    {
+      LOG(ERROR) << "Lua: Bad parameters to HttpGet()";
+      lua_pushstring(state, "ERROR");
+      return 1;
+    }
+
+    // Configure the HTTP client class
+    const char* url = lua_tostring(state, 1);
+    bool isJson = (nArgs >= 2 && lua_toboolean(state, 2));
+    that.httpClient_.SetMethod(HttpMethod_Get);
+    that.httpClient_.SetUrl(url);
+
+    // Do the HTTP GET request
+    if (!that.DoHttpQuery(state, isJson))
+    {
+      LOG(ERROR) << "Lua: Error in HttpGet() for URL " << url;
+      lua_pushstring(state, "ERROR");
+    }
+
+    return 1;
+  }
+
+
+  int LuaContext::CallHttpPostOrPut(lua_State *state,
+                                    HttpMethod method)
+  {
+    LuaContext& that = GetLuaContext(state);
+
+    // Check the types of the arguments
+    int nArgs = lua_gettop(state);
+    if ((nArgs != 1 && nArgs != 2 && nArgs != 3) ||
+        !lua_isstring(state, 1) ||                  // URL
+        (nArgs >= 2 && !lua_isstring(state, 2)) ||  // Body data
+        (nArgs >= 3 && !lua_isboolean(state, 3)))   // Interpret result as JSON
+    {
+      LOG(ERROR) << "Lua: Bad parameters to HttpPost() or HttpPut()";
       lua_pushstring(state, "ERROR");
       return 1;
     }
 
-    // Return the result of the HTTP GET
-    if (isJson)
+    // Configure the HTTP client class
+    const char* url = lua_tostring(state, 1);
+    bool isJson = (nArgs >= 3 && lua_toboolean(state, 3));
+    that.httpClient_.SetMethod(method);
+    that.httpClient_.SetUrl(url);
+
+    if (nArgs >= 2)
     {
-      that.PushJson(json);
+      that.httpClient_.SetPostData(lua_tostring(state, 2));
     }
     else
     {
-      lua_pushstring(state, str.c_str());
+      that.httpClient_.AccessPostData().clear();
+    }
+
+    // Do the HTTP POST/PUT request
+    if (!that.DoHttpQuery(state, isJson))
+    {
+      LOG(ERROR) << "Lua: Error in HttpPost() or HttpPut() for URL " << url;
+      lua_pushstring(state, "ERROR");
+    }
+
+    return 1;
+  }
+
+
+  int LuaContext::CallHttpPost(lua_State *state)
+  {
+    return CallHttpPostOrPut(state, HttpMethod_Post);
+  }
+
+
+  int LuaContext::CallHttpPut(lua_State *state)
+  {
+    return CallHttpPostOrPut(state, HttpMethod_Put);
+  }
+
+
+  int LuaContext::CallHttpDelete(lua_State *state)
+  {
+    LuaContext& that = GetLuaContext(state);
+
+    // Check the types of the arguments
+    int nArgs = lua_gettop(state);
+    if (nArgs != 1 || !lua_isstring(state, 1))  // URL
+    {
+      LOG(ERROR) << "Lua: Bad parameters to HttpDelete()";
+      lua_pushstring(state, "ERROR");
+      return 1;
+    }
+
+    // Configure the HTTP client class
+    const char* url = lua_tostring(state, 1);
+    that.httpClient_.SetMethod(HttpMethod_Delete);
+    that.httpClient_.SetUrl(url);
+
+    // Do the HTTP DELETE request
+    std::string s;
+    if (!that.httpClient_.Apply(s))
+    {
+      LOG(ERROR) << "Lua: Error in HttpPost() for URL " << url;
+      lua_pushstring(state, "ERROR");
+    }
+    else
+    {
+      lua_pushstring(state, "SUCCESS");
     }
 
     return 1;
@@ -233,6 +331,9 @@
     luaL_openlibs(lua_);
     lua_register(lua_, "print", PrintToLog);
     lua_register(lua_, "HttpGet", CallHttpGet);
+    lua_register(lua_, "HttpPost", CallHttpPost);
+    lua_register(lua_, "HttpPut", CallHttpPut);
+    lua_register(lua_, "HttpDelete", CallHttpDelete);
     
     lua_pushlightuserdata(lua_, this);
     lua_setglobal(lua_, "_LuaContext");
--- a/Core/Lua/LuaContext.h	Wed Jul 23 12:59:28 2014 +0200
+++ b/Core/Lua/LuaContext.h	Wed Jul 23 15:08:09 2014 +0200
@@ -56,9 +56,17 @@
 
     static LuaContext& GetLuaContext(lua_State *state);
 
-    static int PrintToLog(lua_State *L);
+    static int PrintToLog(lua_State *state);
 
-    static int CallHttpGet(lua_State *L);
+    static int CallHttpPostOrPut(lua_State *state,
+                                 HttpMethod method);
+    static int CallHttpGet(lua_State *state);
+    static int CallHttpPost(lua_State *state);
+    static int CallHttpPut(lua_State *state);
+    static int CallHttpDelete(lua_State *state);
+
+    bool DoHttpQuery(lua_State* state,
+                     bool isJson);
 
     void Execute(std::string* output,
                  const std::string& command);
@@ -84,5 +92,11 @@
     void Execute(EmbeddedResources::FileResourceId resource);
 
     bool IsExistingFunction(const char* name);
+
+    void SetHttpCredentials(const char* username,
+                            const char* password)
+    {
+      httpClient_.SetCredentials(username, password);
+    }
   };
 }
--- a/UnitTestsSources/LuaTests.cpp	Wed Jul 23 12:59:28 2014 +0200
+++ b/UnitTestsSources/LuaTests.cpp	Wed Jul 23 15:08:09 2014 +0200
@@ -256,4 +256,19 @@
   ASSERT_EQ("MyOrthanc", Orthanc::Toolbox::StripSpaces(s));
 #endif
 
+#if 0
+  lua.Execute(s, "print(HttpPost(\"http://localhost:8042/tools/execute-script\", \"print('hello world')\"))");
+  ASSERT_EQ("hello world", Orthanc::Toolbox::StripSpaces(s));
+
+  lua.Execute(s, "print(HttpPost(\"http://localhost:8042/tools/execute-script\", \"print('[10,42,1000]')\", true)[2])");
+  ASSERT_EQ("42", Orthanc::Toolbox::StripSpaces(s));
+#endif
+
+#if 1
+  lua.Execute(s, "print(HttpGet('http://localhost:8042/modalities'))");
+  lua.Execute(s, "print(HttpPut('http://localhost:8042/modalities/lua', '[ \"ORTHANC\", \"localhost\", 4242 ]'))");
+  lua.Execute(s, "print(HttpGet('http://localhost:8042/modalities'))");
+  lua.Execute(s, "print(HttpDelete('http://localhost:8042/modalities/lua'))");
+  lua.Execute(s, "print(HttpGet('http://localhost:8042/modalities'))");
+#endif
 }