comparison Core/Lua/LuaContext.cpp @ 3442:dd1e68f2d0c0

Fix issue #106 (Unable to export preview as jpeg from Lua script)
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 24 Jun 2019 16:06:47 +0200
parents 4e43e67f8ecf
children 94f4a18a79cc
comparison
equal deleted inserted replaced
3441:6cc72ebfd6ef 3442:dd1e68f2d0c0
34 #include "../PrecompiledHeaders.h" 34 #include "../PrecompiledHeaders.h"
35 #include "LuaContext.h" 35 #include "LuaContext.h"
36 36
37 #include "../Logging.h" 37 #include "../Logging.h"
38 #include "../OrthancException.h" 38 #include "../OrthancException.h"
39 #include "../Toolbox.h"
39 40
40 #include <set> 41 #include <set>
41 #include <cassert> 42 #include <cassert>
42 #include <boost/lexical_cast.hpp> 43 #include <boost/lexical_cast.hpp>
43 44
154 { 155 {
155 keepStrings = lua_toboolean(state, 2) ? true : false; 156 keepStrings = lua_toboolean(state, 2) ? true : false;
156 } 157 }
157 158
158 Json::Value json; 159 Json::Value json;
159 that.GetJson(json, 1, keepStrings); 160 that.GetJson(json, state, 1, keepStrings);
160 161
161 Json::FastWriter writer; 162 Json::FastWriter writer;
162 std::string s = writer.write(json); 163 std::string s = writer.write(json);
163 lua_pushlstring(state, s.c_str(), s.size()); 164 lua_pushlstring(state, s.c_str(), s.size());
164 165
206 // Return the result of the HTTP request 207 // Return the result of the HTTP request
207 lua_pushlstring(state, str.c_str(), str.size()); 208 lua_pushlstring(state, str.c_str(), str.size());
208 209
209 return true; 210 return true;
210 } 211 }
211
212 void LuaContext::SetHttpHeaders(lua_State *state, int top)
213 {
214 this->httpClient_.ClearHeaders(); // always reset headers in case they have been set in a previous request
215
216 if (lua_gettop(state) >= top)
217 {
218 Json::Value headers;
219 this->GetJson(headers, top, true);
220
221 Json::Value::Members members = headers.getMemberNames();
222
223 for (Json::Value::Members::const_iterator
224 it = members.begin(); it != members.end(); ++it)
225 {
226 this->httpClient_.AddHeader(*it, headers[*it].asString());
227 }
228 }
229
230 }
231 212
213
214 void LuaContext::SetHttpHeaders(int top)
215 {
216 std::map<std::string, std::string> headers;
217 GetDictionaryArgument(headers, lua_, top, false /* keep key case as provided by Lua script */);
218
219 httpClient_.ClearHeaders(); // always reset headers in case they have been set in a previous request
220
221 for (std::map<std::string, std::string>::const_iterator
222 it = headers.begin(); it != headers.end(); ++it)
223 {
224 httpClient_.AddHeader(it->first, it->second);
225 }
226 }
232 227
233 228
234 int LuaContext::CallHttpGet(lua_State *state) 229 int LuaContext::CallHttpGet(lua_State *state)
235 { 230 {
236 LuaContext& that = GetLuaContext(state); 231 LuaContext& that = GetLuaContext(state);
237 232
238 // Check the types of the arguments 233 // Check the types of the arguments
239 int nArgs = lua_gettop(state); 234 int nArgs = lua_gettop(state);
240 if ((nArgs < 1 || nArgs > 2) || // check args count 235 if (nArgs < 1 || nArgs > 2 || // check args count
241 !lua_isstring(state, 1)) // URL is a string 236 !lua_isstring(state, 1)) // URL is a string
242 { 237 {
243 LOG(ERROR) << "Lua: Bad parameters to HttpGet()"; 238 LOG(ERROR) << "Lua: Bad parameters to HttpGet()";
244 lua_pushnil(state); 239 lua_pushnil(state);
245 return 1; 240 return 1;
246 } 241 }
248 // Configure the HTTP client class 243 // Configure the HTTP client class
249 const char* url = lua_tostring(state, 1); 244 const char* url = lua_tostring(state, 1);
250 that.httpClient_.SetMethod(HttpMethod_Get); 245 that.httpClient_.SetMethod(HttpMethod_Get);
251 that.httpClient_.SetUrl(url); 246 that.httpClient_.SetUrl(url);
252 that.httpClient_.GetBody().clear(); 247 that.httpClient_.GetBody().clear();
253 that.SetHttpHeaders(state, 2); 248 that.SetHttpHeaders(2);
254 249
255 // Do the HTTP GET request 250 // Do the HTTP GET request
256 if (!that.AnswerHttpQuery(state)) 251 if (!that.AnswerHttpQuery(state))
257 { 252 {
258 LOG(ERROR) << "Lua: Error in HttpGet() for URL " << url; 253 LOG(ERROR) << "Lua: Error in HttpGet() for URL " << url;
281 276
282 // Configure the HTTP client class 277 // Configure the HTTP client class
283 const char* url = lua_tostring(state, 1); 278 const char* url = lua_tostring(state, 1);
284 that.httpClient_.SetMethod(method); 279 that.httpClient_.SetMethod(method);
285 that.httpClient_.SetUrl(url); 280 that.httpClient_.SetUrl(url);
286 that.SetHttpHeaders(state, 3); 281 that.SetHttpHeaders(3);
287 282
288 if (nArgs >= 2 && !lua_isnil(state, 2)) 283 if (nArgs >= 2 && !lua_isnil(state, 2))
289 { 284 {
290 size_t bodySize = 0; 285 size_t bodySize = 0;
291 const char* bodyData = lua_tolstring(state, 2, &bodySize); 286 const char* bodyData = lua_tolstring(state, 2, &bodySize);
343 // Configure the HTTP client class 338 // Configure the HTTP client class
344 const char* url = lua_tostring(state, 1); 339 const char* url = lua_tostring(state, 1);
345 that.httpClient_.SetMethod(HttpMethod_Delete); 340 that.httpClient_.SetMethod(HttpMethod_Delete);
346 that.httpClient_.SetUrl(url); 341 that.httpClient_.SetUrl(url);
347 that.httpClient_.GetBody().clear(); 342 that.httpClient_.GetBody().clear();
348 that.SetHttpHeaders(state, 2); 343 that.SetHttpHeaders(2);
349 344
350 // Do the HTTP DELETE request 345 // Do the HTTP DELETE request
351 std::string s; 346 std::string s;
352 if (!that.httpClient_.Apply(s)) 347 if (!that.httpClient_.Apply(s))
353 { 348 {
432 } 427 }
433 } 428 }
434 429
435 430
436 void LuaContext::GetJson(Json::Value& result, 431 void LuaContext::GetJson(Json::Value& result,
432 lua_State* state,
437 int top, 433 int top,
438 bool keepStrings) 434 bool keepStrings)
439 { 435 {
440 if (lua_istable(lua_, top)) 436 if (lua_istable(state, top))
441 { 437 {
442 Json::Value tmp = Json::objectValue; 438 Json::Value tmp = Json::objectValue;
443 bool isArray = true; 439 bool isArray = true;
444 size_t size = 0; 440 size_t size = 0;
445 441
446 // Code adapted from: http://stackoverflow.com/a/6142700/881731 442 // Code adapted from: http://stackoverflow.com/a/6142700/881731
447 443
448 // Push another reference to the table on top of the stack (so we know 444 // Push another reference to the table on top of the stack (so we know
449 // where it is, and this function can work for negative, positive and 445 // where it is, and this function can work for negative, positive and
450 // pseudo indices 446 // pseudo indices
451 lua_pushvalue(lua_, top); 447 lua_pushvalue(state, top);
452 // stack now contains: -1 => table 448 // stack now contains: -1 => table
453 lua_pushnil(lua_); 449 lua_pushnil(state);
454 // stack now contains: -1 => nil; -2 => table 450 // stack now contains: -1 => nil; -2 => table
455 while (lua_next(lua_, -2)) 451 while (lua_next(state, -2))
456 { 452 {
457 // stack now contains: -1 => value; -2 => key; -3 => table 453 // stack now contains: -1 => value; -2 => key; -3 => table
458 // copy the key so that lua_tostring does not modify the original 454 // copy the key so that lua_tostring does not modify the original
459 lua_pushvalue(lua_, -2); 455 lua_pushvalue(state, -2);
460 // stack now contains: -1 => key; -2 => value; -3 => key; -4 => table 456 // stack now contains: -1 => key; -2 => value; -3 => key; -4 => table
461 std::string key(lua_tostring(lua_, -1)); 457 std::string key(lua_tostring(state, -1));
462 Json::Value v; 458 Json::Value v;
463 GetJson(v, -2, keepStrings); 459 GetJson(v, state, -2, keepStrings);
464 460
465 tmp[key] = v; 461 tmp[key] = v;
466 462
467 size += 1; 463 size += 1;
468 try 464 try
477 { 473 {
478 isArray = false; 474 isArray = false;
479 } 475 }
480 476
481 // pop value + copy of key, leaving original key 477 // pop value + copy of key, leaving original key
482 lua_pop(lua_, 2); 478 lua_pop(state, 2);
483 // stack now contains: -1 => key; -2 => table 479 // stack now contains: -1 => key; -2 => table
484 } 480 }
485 // stack now contains: -1 => table (when lua_next returns 0 it pops the key 481 // stack now contains: -1 => table (when lua_next returns 0 it pops the key
486 // but does not push anything.) 482 // but does not push anything.)
487 // Pop table 483 // Pop table
488 lua_pop(lua_, 1); 484 lua_pop(state, 1);
489 485
490 // Stack is now the same as it was on entry to this function 486 // Stack is now the same as it was on entry to this function
491 487
492 if (isArray) 488 if (isArray)
493 { 489 {
500 else 496 else
501 { 497 {
502 result = tmp; 498 result = tmp;
503 } 499 }
504 } 500 }
505 else if (lua_isnil(lua_, top)) 501 else if (lua_isnil(state, top))
506 { 502 {
507 result = Json::nullValue; 503 result = Json::nullValue;
508 } 504 }
509 else if (!keepStrings && 505 else if (!keepStrings &&
510 lua_isboolean(lua_, top)) 506 lua_isboolean(state, top))
511 { 507 {
512 result = lua_toboolean(lua_, top) ? true : false; 508 result = lua_toboolean(state, top) ? true : false;
513 } 509 }
514 else if (!keepStrings && 510 else if (!keepStrings &&
515 lua_isnumber(lua_, top)) 511 lua_isnumber(state, top))
516 { 512 {
517 // Convert to "int" if truncation does not loose precision 513 // Convert to "int" if truncation does not loose precision
518 double value = static_cast<double>(lua_tonumber(lua_, top)); 514 double value = static_cast<double>(lua_tonumber(state, top));
519 int truncated = static_cast<int>(value); 515 int truncated = static_cast<int>(value);
520 516
521 if (std::abs(value - static_cast<double>(truncated)) <= 517 if (std::abs(value - static_cast<double>(truncated)) <=
522 std::numeric_limits<double>::epsilon()) 518 std::numeric_limits<double>::epsilon())
523 { 519 {
526 else 522 else
527 { 523 {
528 result = value; 524 result = value;
529 } 525 }
530 } 526 }
531 else if (lua_isstring(lua_, top)) 527 else if (lua_isstring(state, top))
532 { 528 {
533 // Caution: The "lua_isstring()" case must be the last, since 529 // Caution: The "lua_isstring()" case must be the last, since
534 // Lua can convert most types to strings by default. 530 // Lua can convert most types to strings by default.
535 result = std::string(lua_tostring(lua_, top)); 531 result = std::string(lua_tostring(state, top));
536 } 532 }
537 else if (lua_isboolean(lua_, top)) 533 else if (lua_isboolean(state, top))
538 { 534 {
539 result = lua_toboolean(lua_, top) ? true : false; 535 result = lua_toboolean(state, top) ? true : false;
540 } 536 }
541 else 537 else
542 { 538 {
543 LOG(WARNING) << "Unsupported Lua type when returning Json"; 539 LOG(WARNING) << "Unsupported Lua type when returning Json";
544 result = Json::nullValue; 540 result = Json::nullValue;
651 assert(lua_type(state, -1) == LUA_TLIGHTUSERDATA); 647 assert(lua_type(state, -1) == LUA_TLIGHTUSERDATA);
652 const void* value = lua_topointer(state, -1); 648 const void* value = lua_topointer(state, -1);
653 lua_pop(state, 1); 649 lua_pop(state, 1);
654 return value; 650 return value;
655 } 651 }
652
653
654 void LuaContext::GetDictionaryArgument(std::map<std::string, std::string>& target,
655 lua_State* state,
656 int top,
657 bool keyToLowerCase)
658 {
659 target.clear();
660
661 if (lua_gettop(state) >= top)
662 {
663 Json::Value headers;
664 GetJson(headers, state, top, true);
665
666 Json::Value::Members members = headers.getMemberNames();
667
668 for (size_t i = 0; i < members.size(); i++)
669 {
670 std::string key = members[i];
671
672 if (keyToLowerCase)
673 {
674 Toolbox::ToLowerCase(key);
675 }
676
677 target[key] = headers[members[i]].asString();
678 }
679 }
680 }
656 } 681 }