# HG changeset patch # User Sebastien Jodogne # Date 1406120889 -7200 # Node ID cc4ff680e2a0bb956c44418bd5c510729981d190 # Parent 92f4bf2c5d73d306aee3ebd27cff96f8cb92aeaa http requests in lua diff -r 92f4bf2c5d73 -r cc4ff680e2a0 Core/HttpClient.cpp --- 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_)); diff -r 92f4bf2c5d73 -r cc4ff680e2a0 Core/HttpClient.h --- 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_; diff -r 92f4bf2c5d73 -r cc4ff680e2a0 Core/Lua/LuaContext.cpp --- 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"); diff -r 92f4bf2c5d73 -r cc4ff680e2a0 Core/Lua/LuaContext.h --- 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); + } }; } diff -r 92f4bf2c5d73 -r cc4ff680e2a0 UnitTestsSources/LuaTests.cpp --- 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 }