main.cpp 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. #include <algorithm>
  2. #include <set>
  3. extern "C"
  4. {
  5. #include <lua.h>
  6. #include <lauxlib.h>
  7. }
  8. #include "../common/HTTPS.h"
  9. #include "../common/config.h"
  10. static std::string validMethod[] = {"GET", "HEAD", "POST", "PUT", "DELETE", "PATCH"};
  11. static int str_toupper(char c)
  12. {
  13. unsigned char uc = (unsigned char) c;
  14. return toupper(uc);
  15. }
  16. static std::string w_checkstring(lua_State *L, int idx)
  17. {
  18. size_t len;
  19. const char *str = luaL_checklstring(L, idx, &len);
  20. return std::string(str, len);
  21. }
  22. static void w_pushstring(lua_State *L, const std::string &str)
  23. {
  24. lua_pushlstring(L, str.data(), str.size());
  25. }
  26. static void w_readheaders(lua_State *L, int idx, HTTPSClient::header_map &headers)
  27. {
  28. if (idx < 0)
  29. idx += lua_gettop(L) + 1;
  30. lua_pushnil(L);
  31. while (lua_next(L, idx))
  32. {
  33. auto header = w_checkstring(L, -2);
  34. headers[header] = w_checkstring(L, -1);
  35. lua_pop(L, 1);
  36. }
  37. lua_pop(L, 1);
  38. }
  39. static std::string w_optmethod(lua_State *L, int idx, const std::string &defaultMethod)
  40. {
  41. std::string *const validMethodEnd = validMethod + sizeof(validMethod) / sizeof(std::string);
  42. if (lua_isnoneornil(L, idx))
  43. return defaultMethod;
  44. std::string str = w_checkstring(L, idx);
  45. std::transform(str.begin(), str.end(), str.begin(), str_toupper);
  46. if (std::find(validMethod, validMethodEnd, str) == validMethodEnd)
  47. luaL_argerror(L, idx, "expected one of \"get\", \"head\", \"post\", \"put\", \"delete\", or \"patch\"");
  48. return str;
  49. }
  50. static int w_request(lua_State *L)
  51. {
  52. auto url = w_checkstring(L, 1);
  53. HTTPSClient::Request req(url);
  54. bool advanced = false;
  55. if (lua_istable(L, 2))
  56. {
  57. advanced = true;
  58. std::string defaultMethod = "GET";
  59. lua_getfield(L, 2, "data");
  60. if (!lua_isnoneornil(L, -1))
  61. {
  62. req.postdata = w_checkstring(L, -1);
  63. defaultMethod = "POST";
  64. }
  65. lua_pop(L, 1);
  66. lua_getfield(L, 2, "method");
  67. req.method = w_optmethod(L, -1, defaultMethod);
  68. lua_pop(L, 1);
  69. lua_getfield(L, 2, "headers");
  70. if (!lua_isnoneornil(L, -1))
  71. w_readheaders(L, -1, req.headers);
  72. lua_pop(L, 1);
  73. }
  74. HTTPSClient::Reply reply;
  75. try
  76. {
  77. reply = request(req);
  78. }
  79. catch (const std::exception& e)
  80. {
  81. std::string errorMessage = e.what();
  82. lua_pushnil(L);
  83. lua_pushstring(L, errorMessage.c_str());
  84. return 2;
  85. }
  86. lua_pushinteger(L, reply.responseCode);
  87. w_pushstring(L, reply.body);
  88. if (advanced)
  89. {
  90. lua_newtable(L);
  91. for (const auto &header : reply.headers)
  92. {
  93. w_pushstring(L, header.first);
  94. w_pushstring(L, header.second);
  95. lua_settable(L, -3);
  96. }
  97. }
  98. return advanced ? 3 : 2;
  99. }
  100. extern "C" int HTTPS_DLLEXPORT luaopen_https(lua_State *L)
  101. {
  102. lua_newtable(L);
  103. lua_pushcfunction(L, w_request);
  104. lua_setfield(L, -2, "request");
  105. return 1;
  106. }