main.cpp 3.7 KB

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