luat_lib_http.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. /*
  2. @module http
  3. @summary 执行http请求
  4. @version 1.0
  5. @date 2020.07.07
  6. */
  7. #include "luat_base.h"
  8. #include "luat_http.h"
  9. #include "luat_msgbus.h"
  10. #include "luat_malloc.h"
  11. #define LUAT_LOG_TAG "http"
  12. #include "luat_log.h"
  13. static int l_http_reqcommon(lua_State *L, uint8_t method);
  14. static int luat_http_msghandler(lua_State *L, void* ptr) {
  15. luat_lib_http_resp_t *resp = ptr;
  16. int recount = 0;
  17. if (resp) {
  18. LLOGD("http resp code=%ld", resp->code);
  19. if (resp->luacb) {
  20. lua_geti(L, LUA_REGISTRYINDEX, resp->luacb);
  21. lua_pushinteger(L, resp->code);
  22. lua_newtable(L); // headers 暂时不处理
  23. if (resp->body.size > 0) {
  24. recount = 3;
  25. lua_pushlstring(L, resp->body.ptr, resp->body.size);
  26. }
  27. else {
  28. recount = 2;
  29. }
  30. lua_call(L, recount, 0);
  31. luaL_unref(L, LUA_REGISTRYINDEX, resp->luacb);
  32. }
  33. luat_http_resp_gc(resp);
  34. }
  35. return 0;
  36. }
  37. static int luat_http_cb_impl(luat_lib_http_resp_t *resp) {
  38. if (resp->luacb == 0) {
  39. LLOGD("http resp without lua callback code=%ld", resp->code);
  40. luat_http_resp_gc(resp);
  41. return 0; //
  42. }
  43. rtos_msg_t msg;
  44. msg.handler = luat_http_msghandler;
  45. msg.ptr = resp;
  46. msg.arg1 = resp->code;
  47. msg.arg2 = 0;
  48. luat_msgbus_put(&msg, 0);
  49. return 0;
  50. }
  51. /*
  52. 发起一个http get请求(推荐用http.get/post/put/delete方法)
  53. @api http.req(url, params, cb)
  54. @string 目标URL,需要是https://或者http://开头,否则将当成http://开头
  55. @table 可选参数. method方法,headers请求头,body数据,ca证书路径,timeout超时时长,
  56. @function 回调方法
  57. @return boolean 成功启动返回true,否则返回false.启动成功后,cb回调必然会调用一次
  58. @usage
  59. -- GET请求
  60. http.req("http://www.baidu.com/", nil, function(ret, code, headers, body)
  61. log.info("http", ret, code, header, body)
  62. end)
  63. */
  64. static int l_http_req(lua_State *L) {
  65. return l_http_reqcommon(L, LUAT_HTTP_GET);
  66. }
  67. /*
  68. 发起一个http get请求
  69. @api http.get(url, params, cb)
  70. @string 目标URL,需要是https://或者http://开头,否则将当成http://开头
  71. @table 可选参数. headers请求头,body数据,ca证书路径,timeout超时时长,
  72. @function 回调方法
  73. @return boolean 成功启动返回true,否则返回false.启动成功后,cb回调必然会调用一次
  74. @usage
  75. -- GET请求
  76. http.get("http://www.baidu.com/", nil, function(ret, code, headers, body)
  77. log.info("http", ret, code, header, body)
  78. end)
  79. */
  80. static int l_http_get(lua_State *L) {
  81. return l_http_reqcommon(L, LUAT_HTTP_GET);
  82. }
  83. /*
  84. 发起一个http post请求
  85. @api http.post(url, params, cb)
  86. @string 目标URL,需要是https://或者http://开头,否则将当成http://开头
  87. @table 可选参数. headers请求头,body数据,ca证书路径,timeout超时时长,
  88. @function 回调方法
  89. @return boolean 成功启动返回true,否则返回false.启动成功后,cb回调必然会调用一次
  90. @usage
  91. -- POST请求
  92. http.post("http://www.baidu.com/", {body=json.encode(data)}, function(ret, code, headers, body)
  93. log.info("http", ret, code, header, body)
  94. end)
  95. */
  96. static int l_http_post(lua_State *L) {
  97. return l_http_reqcommon(L, LUAT_HTTP_POST);
  98. }
  99. /*
  100. 发起一个http put请求
  101. @api http.put(url, params, cb)
  102. @string 目标URL,需要是https://或者http://开头,否则将当成http://开头
  103. @table 可选参数. headers请求头,body数据,ca证书路径,timeout超时时长,
  104. @function 回调方法
  105. @return boolean 成功启动返回true,否则返回false.启动成功后,cb回调必然会调用一次
  106. @usage
  107. -- PUT请求
  108. http.put("http://www.baidu.com/", {body=json.encode(data)}, function(ret, code, headers, body)
  109. log.info("http", ret, code, header, body)
  110. end)
  111. */
  112. static int l_http_put(lua_State *L) {
  113. return l_http_reqcommon(L, LUAT_HTTP_PUT);
  114. }
  115. /*
  116. 发起一个http delete请求
  117. @api http.delete(url, params, cb)
  118. @string 目标URL,需要是https://或者http://开头,否则将当成http://开头
  119. @table 可选参数. headers请求头,body数据,ca证书路径,timeout超时时长,
  120. @function 回调方法
  121. @return boolean 成功启动返回true,否则返回false.启动成功后,cb回调必然会调用一次
  122. @usage
  123. -- DELETE请求
  124. http.delete("http://www.baidu.com/", nil, function(ret, code, headers, body)
  125. log.info("http", ret, code, header, body)
  126. end)
  127. */
  128. static int l_http_delete(lua_State *L) {
  129. return l_http_reqcommon(L, LUAT_HTTP_DELETE);
  130. }
  131. static int l_http_reqcommon(lua_State *L, uint8_t method) {
  132. if (!lua_isstring(L, 1)) {
  133. lua_pushliteral(L, "first arg must string");
  134. lua_error(L);
  135. return 0;
  136. }
  137. luat_lib_http_req_t *req = luat_heap_malloc(sizeof(luat_lib_http_req_t));
  138. if (req == NULL) {
  139. lua_pushstring(L, "sys out of memory");
  140. lua_error(L);
  141. return 0;
  142. }
  143. memset(req, 0, sizeof(luat_lib_http_req_t));
  144. req->method = method;
  145. char* tmp = (char*)luaL_checklstring(L, 1, &(req->url_len));
  146. req->url = luat_heap_malloc(req->url_len+1);
  147. if (req->url == NULL) {
  148. luat_heap_free(req);
  149. lua_pushstring(L, "sys out of memory");
  150. lua_error(L);
  151. return 0;
  152. }
  153. memset(req->url, 0, req->url_len + 1);
  154. memcpy(req->url, tmp, req->url_len + 1);
  155. LLOGD("http url=%s", req->url);
  156. // 先取一下回调
  157. if (lua_isfunction(L, 3)) {
  158. lua_settop(L, 3);
  159. req->luacb = luaL_ref(L, LUA_REGISTRYINDEX);
  160. }
  161. if (lua_istable(L, 2)) {
  162. //lua_settop(L, 2); // 移除掉其他参数
  163. // 取method
  164. lua_pushliteral(L, "method");
  165. if (lua_gettable(L, 2)) {
  166. if (lua_isinteger(L, -1)) {
  167. req->method = luaL_checkinteger(L, -1);
  168. }
  169. }
  170. lua_pop(L, 1);
  171. // 取下载路径
  172. lua_pushliteral(L, "dw");
  173. if (lua_gettable(L, 2) == LUA_TSTRING){
  174. size_t dw_path_sz = 0;
  175. const char* dw = luaL_checklstring(L, -1, &dw_path_sz);
  176. if (dw_path_sz > 31) {
  177. LLOGD("download path is too long!!!");
  178. lua_pushliteral(L, "download path is too long!!!");
  179. lua_error(L);
  180. return 0;
  181. }
  182. strcpy(req->dwpath, dw);
  183. }
  184. lua_pop(L, 1);
  185. // 取headers
  186. // 取body,当前仅支持string
  187. lua_pushliteral(L, "body");
  188. lua_gettable(L, 2);
  189. if (!lua_isnil(L, -1) && !lua_isstring(L, -1)) {
  190. lua_pop(L, 1);
  191. lua_pushliteral(L, "body must be string");
  192. lua_error(L);
  193. luat_http_req_gc(req);
  194. return 0;
  195. }
  196. else if (lua_isstring(L, -1)) {
  197. tmp = (char*)luaL_checklstring(L, -1, &(req->body.size));
  198. if (req->body.size > 0) {
  199. req->body.ptr = luat_heap_malloc(req->body.size);
  200. memcpy(req->body.ptr, tmp, req->body.size);
  201. }
  202. }
  203. lua_pop(L, 1);
  204. // 去ca证书路径
  205. lua_pushliteral(L, "ca");
  206. lua_gettable(L, 2);
  207. if (!lua_isnil(L, -1) && !lua_isstring(L, -1)) {
  208. lua_pop(L, 1);
  209. lua_pushliteral(L, "ca must be string");
  210. lua_error(L);
  211. luat_http_req_gc(req);
  212. return 0;
  213. }
  214. else if (lua_isstring(L, -1)) {
  215. tmp = (char*)luaL_checklstring(L, -1, &(req->ca_len));
  216. if (req->ca_len > 0) {
  217. req->ca = luat_heap_malloc(req->ca_len);
  218. memcpy(req->ca, tmp, req->ca_len);
  219. }
  220. }
  221. lua_pop(L, 1);
  222. // timeout设置
  223. lua_pushliteral(L, "timeout");
  224. lua_gettable(L, 2);
  225. if (!lua_isnil(L, -1) && !lua_isinteger(L, -1)) {
  226. lua_pop(L, 1);
  227. lua_pushliteral(L, "timeout must be int");
  228. lua_error(L);
  229. luat_http_req_gc(req);
  230. return 0;
  231. }
  232. else if (lua_isinteger(L, -1)) {
  233. req->timeout_s = luaL_checkinteger(L, -1);
  234. }
  235. lua_pop(L, 1);
  236. }
  237. req->httpcb = luat_http_cb_impl;
  238. if (req->timeout_s <= 5) {
  239. req->timeout_s = 5;
  240. }
  241. // 执行
  242. int re = luat_http_req(req);
  243. if (re == 0) {
  244. lua_pushboolean(L, 1);
  245. return 1;
  246. }
  247. else {
  248. luat_http_req_gc(req);
  249. LLOGW("http request return re=%ld", re);
  250. lua_pushboolean(L, 0);
  251. lua_pushinteger(L, re);
  252. return 2;
  253. }
  254. }
  255. #include "rotable.h"
  256. static const rotable_Reg reg_http[] =
  257. {
  258. { "req", l_http_req, 0},
  259. { "get", l_http_get, 0},
  260. { "post", l_http_post, 0},
  261. { "put", l_http_put, 0},
  262. { "delete", l_http_delete, 0},
  263. { NULL, NULL, 0}
  264. };
  265. LUAMOD_API int luaopen_http( lua_State *L ) {
  266. luat_newlib(L, reg_http);
  267. return 1;
  268. }
  269. void luat_http_req_gc(luat_lib_http_req_t *req) {
  270. if (req == NULL) {
  271. return;
  272. }
  273. if (req->url) {
  274. luat_heap_free(req->url);
  275. }
  276. if (req->headers.size > 0) {
  277. for (size_t i = 0; i < req->headers.size; i++)
  278. {
  279. luat_heap_free(*(req->headers.ptr + i));
  280. }
  281. }
  282. if (req->body.size > 0) {
  283. luat_heap_free(req->body.ptr);
  284. }
  285. luat_heap_free(req);
  286. }
  287. void luat_http_resp_gc(luat_lib_http_resp_t *resp) {
  288. if (resp == NULL) {
  289. return;
  290. }
  291. if (resp->headers.size > 0) {
  292. for (size_t i = 0; i < resp->headers.size; i++)
  293. {
  294. luat_heap_free(*(resp->headers.ptr + i));
  295. }
  296. }
  297. if (resp->body.size > 0) {
  298. luat_heap_free(resp->body.ptr);
  299. }
  300. luat_heap_free(resp);
  301. }