main.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. #include <lua.hpp>
  2. // Sorry for the ifdef soup ahead
  3. #include "common/config.h"
  4. #include "common/HTTPSClient.h"
  5. #include "common/ConnectionClient.h"
  6. #ifdef USE_CURL_BACKEND
  7. # include "generic/CurlClient.h"
  8. #endif
  9. #ifdef USE_OPENSSL_BACKEND
  10. # include "generic/OpenSSLConnection.h"
  11. #endif
  12. #ifdef USE_SCHANNEL_BACKEND
  13. # include "windows/SChannelConnection.h"
  14. #endif
  15. #ifdef USE_NSURL_BACKEND
  16. # include "macos/NSURLClient.h"
  17. #endif
  18. #ifdef USE_CURL_BACKEND
  19. static CurlClient curlclient;
  20. #endif
  21. #ifdef USE_OPENSSL_BACKEND
  22. static ConnectionClient<OpenSSLConnection> opensslclient;
  23. #endif
  24. #ifdef USE_SCHANNEL_BACKEND
  25. static ConnectionClient<SChannelConnection> schannelclient;
  26. #endif
  27. #ifdef USE_NSURL_BACKEND
  28. static NSURLClient nsurlclient;
  29. #endif
  30. static HTTPSClient *clients[] = {
  31. #ifdef USE_CURL_BACKEND
  32. &curlclient,
  33. #endif
  34. #ifdef USE_OPENSSL_BACKEND
  35. &opensslclient,
  36. #endif
  37. #ifdef USE_SCHANNEL_BACKEND
  38. &schannelclient,
  39. #endif
  40. #ifdef USE_NSURL_BACKEND
  41. &nsurlclient,
  42. #endif
  43. nullptr,
  44. };
  45. static std::string w_checkstring(lua_State *L, int idx)
  46. {
  47. size_t len;
  48. const char *str = luaL_checklstring(L, idx, &len);
  49. return std::string(str, len);
  50. }
  51. static void w_pushstring(lua_State *L, const std::string &str)
  52. {
  53. lua_pushlstring(L, str.data(), str.size());
  54. }
  55. static void w_readheaders(lua_State *L, int idx, HTTPSClient::header_map &headers)
  56. {
  57. if (idx < 0)
  58. idx += lua_gettop(L) + 1;
  59. lua_pushnil(L);
  60. while (lua_next(L, idx))
  61. {
  62. auto header = w_checkstring(L, -2);
  63. headers[header] = w_checkstring(L, -1);
  64. lua_pop(L, 1);
  65. }
  66. lua_pop(L, 1);
  67. }
  68. static HTTPSClient::Request::Method w_optmethod(lua_State *L, int idx, HTTPSClient::Request::Method defaultMethod)
  69. {
  70. if (lua_isnoneornil(L, idx))
  71. return defaultMethod;
  72. auto str = w_checkstring(L, idx);
  73. if (str == "get")
  74. return HTTPSClient::Request::GET;
  75. else if (str == "post")
  76. return HTTPSClient::Request::POST;
  77. else
  78. luaL_argerror(L, idx, "expected one of \"get\" or \"set\"");
  79. return defaultMethod;
  80. }
  81. static int w_request(lua_State *L)
  82. {
  83. auto url = w_checkstring(L, 1);
  84. HTTPSClient::Request req(url);
  85. std::string errorMessage("No applicable implementation found");
  86. bool foundClient = false;
  87. bool advanced = false;
  88. if (lua_istable(L, 2))
  89. {
  90. advanced = true;
  91. HTTPSClient::Request::Method defaultMethod = HTTPSClient::Request::GET;
  92. lua_getfield(L, 2, "data");
  93. if (!lua_isnoneornil(L, -1))
  94. {
  95. req.postdata = w_checkstring(L, -1);
  96. defaultMethod = HTTPSClient::Request::POST;
  97. }
  98. lua_pop(L, 1);
  99. lua_getfield(L, 2, "method");
  100. req.method = w_optmethod(L, -1, defaultMethod);
  101. lua_pop(L, 1);
  102. lua_getfield(L, 2, "headers");
  103. if (!lua_isnoneornil(L, -1))
  104. w_readheaders(L, -1, req.headers);
  105. lua_pop(L, 1);
  106. }
  107. for (size_t i = 0; clients[i]; ++i)
  108. {
  109. HTTPSClient &client = *clients[i];
  110. HTTPSClient::Reply reply;
  111. if (!client.valid())
  112. continue;
  113. try
  114. {
  115. reply = client.request(req);
  116. }
  117. catch(const std::exception& e)
  118. {
  119. errorMessage = e.what();
  120. break;
  121. }
  122. lua_pushinteger(L, reply.responseCode);
  123. w_pushstring(L, reply.body);
  124. if (advanced)
  125. {
  126. lua_newtable(L);
  127. for (const auto &header : reply.headers)
  128. {
  129. w_pushstring(L, header.first);
  130. w_pushstring(L, header.second);
  131. lua_settable(L, -3);
  132. }
  133. }
  134. foundClient = true;
  135. break;
  136. }
  137. if (!foundClient)
  138. {
  139. lua_pushnil(L);
  140. lua_pushstring(L, errorMessage.c_str());
  141. }
  142. return (advanced && foundClient) ? 3 : 2;
  143. }
  144. extern "C" int DLLEXPORT luaopen_https(lua_State *L)
  145. {
  146. lua_newtable(L);
  147. lua_pushcfunction(L, w_request);
  148. lua_setfield(L, -2, "request");
  149. return 1;
  150. }