Mercurial > hg > orthanc
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 } |