luat_lib_http.c 9.5 KB

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