You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

lua_xmlrpc.c 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796
  1. /*-
  2. * Copyright 2016 Vsevolod Stakhov
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "lua_common.h"
  17. LUA_FUNCTION_DEF(xmlrpc, parse_reply);
  18. LUA_FUNCTION_DEF(xmlrpc, make_request);
  19. static const struct luaL_reg xmlrpclib_m[] = {
  20. LUA_INTERFACE_DEF(xmlrpc, parse_reply),
  21. LUA_INTERFACE_DEF(xmlrpc, make_request),
  22. {"__tostring", rspamd_lua_class_tostring},
  23. {NULL, NULL}};
  24. #define msg_debug_xmlrpc(...) rspamd_conditional_debug_fast(NULL, NULL, \
  25. rspamd_xmlrpc_log_id, "xmlrpc", "", \
  26. RSPAMD_LOG_FUNC, \
  27. __VA_ARGS__)
  28. INIT_LOG_MODULE(xmlrpc)
  29. enum lua_xmlrpc_state {
  30. read_method_response = 0,
  31. read_params = 1,
  32. read_param = 2,
  33. read_param_value = 3,
  34. read_param_element = 4,
  35. read_struct = 5,
  36. read_struct_member_name = 6,
  37. read_struct_member_value = 7,
  38. read_struct_element = 8,
  39. read_string = 9,
  40. read_int = 10,
  41. read_double = 11,
  42. read_array = 12,
  43. read_array_value = 13,
  44. read_array_element = 14,
  45. error_state = 99,
  46. success_state = 100,
  47. };
  48. enum lua_xmlrpc_stack {
  49. st_array = 1,
  50. st_struct = 2,
  51. };
  52. struct lua_xmlrpc_ud {
  53. enum lua_xmlrpc_state parser_state;
  54. GQueue *st;
  55. int param_count;
  56. gboolean got_text;
  57. lua_State *L;
  58. };
  59. static void xmlrpc_start_element(GMarkupParseContext *context,
  60. const char *name,
  61. const char **attribute_names,
  62. const char **attribute_values,
  63. gpointer user_data,
  64. GError **error);
  65. static void xmlrpc_end_element(GMarkupParseContext *context,
  66. const char *element_name,
  67. gpointer user_data,
  68. GError **error);
  69. static void xmlrpc_error(GMarkupParseContext *context,
  70. GError *error,
  71. gpointer user_data);
  72. static void xmlrpc_text(GMarkupParseContext *context,
  73. const char *text,
  74. gsize text_len,
  75. gpointer user_data,
  76. GError **error);
  77. static GMarkupParser xmlrpc_parser = {
  78. .start_element = xmlrpc_start_element,
  79. .end_element = xmlrpc_end_element,
  80. .passthrough = NULL,
  81. .text = xmlrpc_text,
  82. .error = xmlrpc_error,
  83. };
  84. static GQuark
  85. xmlrpc_error_quark(void)
  86. {
  87. return g_quark_from_static_string("xmlrpc-error-quark");
  88. }
  89. static void
  90. xmlrpc_start_element(GMarkupParseContext *context,
  91. const char *name,
  92. const char **attribute_names,
  93. const char **attribute_values,
  94. gpointer user_data,
  95. GError **error)
  96. {
  97. struct lua_xmlrpc_ud *ud = user_data;
  98. enum lua_xmlrpc_state last_state;
  99. last_state = ud->parser_state;
  100. msg_debug_xmlrpc("got start element %s on state %d", name, last_state);
  101. switch (ud->parser_state) {
  102. case read_method_response:
  103. /* Expect tag methodResponse */
  104. if (g_ascii_strcasecmp(name, "methodResponse") == 0) {
  105. ud->parser_state = read_params;
  106. }
  107. else {
  108. /* Error state */
  109. ud->parser_state = error_state;
  110. }
  111. break;
  112. case read_params:
  113. /* Expect tag params */
  114. if (g_ascii_strcasecmp(name, "params") == 0) {
  115. ud->parser_state = read_param;
  116. /* result -> table of params indexed by int */
  117. lua_newtable(ud->L);
  118. }
  119. else {
  120. /* Error state */
  121. ud->parser_state = error_state;
  122. }
  123. break;
  124. case read_param:
  125. /* Expect tag param */
  126. if (g_ascii_strcasecmp(name, "param") == 0) {
  127. ud->parser_state = read_param_value;
  128. /* Create new param */
  129. }
  130. else {
  131. /* Error state */
  132. ud->parser_state = error_state;
  133. }
  134. break;
  135. case read_param_value:
  136. /* Expect tag value */
  137. if (g_ascii_strcasecmp(name, "value") == 0) {
  138. ud->parser_state = read_param_element;
  139. }
  140. else {
  141. /* Error state */
  142. ud->parser_state = error_state;
  143. }
  144. break;
  145. case read_param_element:
  146. /* Expect tag struct */
  147. if (g_ascii_strcasecmp(name, "struct") == 0) {
  148. ud->parser_state = read_struct;
  149. /* Create new param of table type */
  150. lua_newtable(ud->L);
  151. g_queue_push_head(ud->st, GINT_TO_POINTER(st_struct));
  152. msg_debug_xmlrpc("push struct");
  153. }
  154. else if (g_ascii_strcasecmp(name, "array") == 0) {
  155. ud->parser_state = read_array;
  156. /* Create new param of table type */
  157. lua_newtable(ud->L);
  158. g_queue_push_head(ud->st, GINT_TO_POINTER(st_array));
  159. msg_debug_xmlrpc("push array");
  160. }
  161. else if (g_ascii_strcasecmp(name, "string") == 0) {
  162. ud->parser_state = read_string;
  163. ud->got_text = FALSE;
  164. }
  165. else if (g_ascii_strcasecmp(name, "int") == 0) {
  166. ud->parser_state = read_int;
  167. ud->got_text = FALSE;
  168. }
  169. else if (g_ascii_strcasecmp(name, "double") == 0) {
  170. ud->parser_state = read_double;
  171. ud->got_text = FALSE;
  172. }
  173. else {
  174. /* Error state */
  175. ud->parser_state = error_state;
  176. }
  177. break;
  178. case read_struct:
  179. /* Parse structure */
  180. /* Expect tag member */
  181. if (g_ascii_strcasecmp(name, "member") == 0) {
  182. ud->parser_state = read_struct_member_name;
  183. }
  184. else {
  185. /* Error state */
  186. ud->parser_state = error_state;
  187. }
  188. break;
  189. case read_struct_member_name:
  190. /* Expect tag name */
  191. if (g_ascii_strcasecmp(name, "name") == 0) {
  192. ud->parser_state = read_struct_member_value;
  193. }
  194. else {
  195. /* Error state */
  196. ud->parser_state = error_state;
  197. }
  198. break;
  199. case read_struct_member_value:
  200. /* Accept value */
  201. if (g_ascii_strcasecmp(name, "value") == 0) {
  202. ud->parser_state = read_struct_element;
  203. }
  204. else {
  205. /* Error state */
  206. ud->parser_state = error_state;
  207. }
  208. break;
  209. case read_struct_element:
  210. /* Parse any values */
  211. /* Primitives */
  212. if (g_ascii_strcasecmp(name, "string") == 0) {
  213. ud->parser_state = read_string;
  214. ud->got_text = FALSE;
  215. }
  216. else if (g_ascii_strcasecmp(name, "int") == 0) {
  217. ud->parser_state = read_int;
  218. ud->got_text = FALSE;
  219. }
  220. else if (g_ascii_strcasecmp(name, "double") == 0) {
  221. ud->parser_state = read_double;
  222. ud->got_text = FALSE;
  223. }
  224. /* Structure */
  225. else if (g_ascii_strcasecmp(name, "struct") == 0) {
  226. ud->parser_state = read_struct;
  227. /* Create new param of table type */
  228. lua_newtable(ud->L);
  229. g_queue_push_head(ud->st, GINT_TO_POINTER(st_struct));
  230. msg_debug_xmlrpc("push struct");
  231. }
  232. else if (g_ascii_strcasecmp(name, "array") == 0) {
  233. ud->parser_state = read_array;
  234. /* Create new param of table type */
  235. lua_newtable(ud->L);
  236. g_queue_push_head(ud->st, GINT_TO_POINTER(st_array));
  237. msg_debug_xmlrpc("push array");
  238. }
  239. else {
  240. /* Error state */
  241. ud->parser_state = error_state;
  242. }
  243. break;
  244. case read_array:
  245. /* Parse array */
  246. /* Expect data */
  247. if (g_ascii_strcasecmp(name, "data") == 0) {
  248. ud->parser_state = read_array_value;
  249. }
  250. else {
  251. /* Error state */
  252. ud->parser_state = error_state;
  253. }
  254. break;
  255. case read_array_value:
  256. /* Accept array value */
  257. if (g_ascii_strcasecmp(name, "value") == 0) {
  258. ud->parser_state = read_array_element;
  259. }
  260. else {
  261. /* Error state */
  262. ud->parser_state = error_state;
  263. }
  264. break;
  265. case read_array_element:
  266. /* Parse any values */
  267. /* Primitives */
  268. if (g_ascii_strcasecmp(name, "string") == 0) {
  269. ud->parser_state = read_string;
  270. ud->got_text = FALSE;
  271. }
  272. else if (g_ascii_strcasecmp(name, "int") == 0) {
  273. ud->parser_state = read_int;
  274. ud->got_text = FALSE;
  275. }
  276. else if (g_ascii_strcasecmp(name, "double") == 0) {
  277. ud->parser_state = read_double;
  278. ud->got_text = FALSE;
  279. }
  280. /* Structure */
  281. else if (g_ascii_strcasecmp(name, "struct") == 0) {
  282. ud->parser_state = read_struct;
  283. /* Create new param of table type */
  284. lua_newtable(ud->L);
  285. g_queue_push_head(ud->st, GINT_TO_POINTER(st_struct));
  286. msg_debug_xmlrpc("push struct");
  287. }
  288. else if (g_ascii_strcasecmp(name, "array") == 0) {
  289. ud->parser_state = read_array;
  290. /* Create new param of table type */
  291. lua_newtable(ud->L);
  292. g_queue_push_head(ud->st, GINT_TO_POINTER(st_array));
  293. msg_debug_xmlrpc("push array");
  294. }
  295. else {
  296. /* Error state */
  297. ud->parser_state = error_state;
  298. }
  299. break;
  300. default:
  301. break;
  302. }
  303. msg_debug_xmlrpc("switched state on start tag %d->%d", last_state,
  304. ud->parser_state);
  305. if (ud->parser_state == error_state) {
  306. g_set_error(error,
  307. xmlrpc_error_quark(), 1, "xmlrpc parse error on state: %d, while parsing start tag: %s",
  308. last_state, name);
  309. }
  310. }
  311. static void
  312. xmlrpc_end_element(GMarkupParseContext *context,
  313. const char *name,
  314. gpointer user_data,
  315. GError **error)
  316. {
  317. struct lua_xmlrpc_ud *ud = user_data;
  318. enum lua_xmlrpc_state last_state;
  319. int last_queued;
  320. last_state = ud->parser_state;
  321. msg_debug_xmlrpc("got end element %s on state %d", name, last_state);
  322. switch (ud->parser_state) {
  323. case read_method_response:
  324. ud->parser_state = error_state;
  325. break;
  326. case read_params:
  327. /* Got methodResponse */
  328. if (g_ascii_strcasecmp(name, "methodResponse") == 0) {
  329. /* End processing */
  330. ud->parser_state = success_state;
  331. }
  332. else {
  333. /* Error state */
  334. ud->parser_state = error_state;
  335. }
  336. break;
  337. case read_param:
  338. /* Got tag params */
  339. if (g_ascii_strcasecmp(name, "params") == 0) {
  340. ud->parser_state = read_params;
  341. }
  342. else {
  343. /* Error state */
  344. ud->parser_state = error_state;
  345. }
  346. break;
  347. case read_param_value:
  348. /* Got tag param */
  349. if (g_ascii_strcasecmp(name, "param") == 0) {
  350. ud->parser_state = read_param;
  351. lua_rawseti(ud->L, -2, ++ud->param_count);
  352. msg_debug_xmlrpc("set param element idx: %d", ud->param_count);
  353. }
  354. else {
  355. /* Error state */
  356. ud->parser_state = error_state;
  357. }
  358. break;
  359. case read_param_element:
  360. /* Got tag value */
  361. if (g_ascii_strcasecmp(name, "value") == 0) {
  362. if (g_queue_get_length(ud->st) == 0) {
  363. ud->parser_state = read_param_value;
  364. }
  365. else {
  366. if (GPOINTER_TO_INT(g_queue_peek_head(ud->st)) == st_struct) {
  367. ud->parser_state = read_struct_member_name;
  368. }
  369. else {
  370. ud->parser_state = read_array_value;
  371. }
  372. }
  373. }
  374. else {
  375. /* Error state */
  376. ud->parser_state = error_state;
  377. }
  378. break;
  379. case read_struct:
  380. /* Got tag struct */
  381. if (g_ascii_strcasecmp(name, "struct") == 0) {
  382. g_assert(GPOINTER_TO_INT(g_queue_pop_head(ud->st)) == st_struct);
  383. if (g_queue_get_length(ud->st) == 0) {
  384. ud->parser_state = read_param_element;
  385. }
  386. else {
  387. last_queued = GPOINTER_TO_INT(g_queue_peek_head(ud->st));
  388. if (last_queued == st_struct) {
  389. ud->parser_state = read_struct_element;
  390. }
  391. else {
  392. ud->parser_state = read_array_element;
  393. }
  394. }
  395. msg_debug_xmlrpc("pop struct");
  396. }
  397. else {
  398. /* Error state */
  399. ud->parser_state = error_state;
  400. }
  401. break;
  402. case read_struct_member_name:
  403. /* Got tag member */
  404. if (g_ascii_strcasecmp(name, "member") == 0) {
  405. ud->parser_state = read_struct;
  406. /* Set table */
  407. msg_debug_xmlrpc("set struct element idx: %s",
  408. lua_tostring(ud->L, -2));
  409. lua_settable(ud->L, -3);
  410. }
  411. else {
  412. /* Error state */
  413. ud->parser_state = error_state;
  414. }
  415. break;
  416. case read_struct_member_value:
  417. /* Got tag name */
  418. if (g_ascii_strcasecmp(name, "name") == 0) {
  419. ud->parser_state = read_struct_member_value;
  420. }
  421. else {
  422. /* Error state */
  423. ud->parser_state = error_state;
  424. }
  425. break;
  426. case read_struct_element:
  427. /* Got tag value */
  428. if (g_ascii_strcasecmp(name, "value") == 0) {
  429. ud->parser_state = read_struct_member_name;
  430. }
  431. else {
  432. /* Error state */
  433. ud->parser_state = error_state;
  434. }
  435. break;
  436. case read_string:
  437. case read_int:
  438. case read_double:
  439. /* Parse any values */
  440. /* Handle empty tags */
  441. if (!ud->got_text) {
  442. lua_pushnil(ud->L);
  443. }
  444. else {
  445. ud->got_text = FALSE;
  446. }
  447. /* Primitives */
  448. if (g_ascii_strcasecmp(name, "string") == 0 ||
  449. g_ascii_strcasecmp(name, "int") == 0 ||
  450. g_ascii_strcasecmp(name, "double") == 0) {
  451. if (GPOINTER_TO_INT(g_queue_peek_head(ud->st)) == st_struct) {
  452. ud->parser_state = read_struct_element;
  453. }
  454. else {
  455. ud->parser_state = read_array_element;
  456. }
  457. }
  458. else {
  459. /* Error state */
  460. ud->parser_state = error_state;
  461. }
  462. break;
  463. case read_array:
  464. /* Got tag array */
  465. if (g_ascii_strcasecmp(name, "array") == 0) {
  466. g_assert(GPOINTER_TO_INT(g_queue_pop_head(ud->st)) == st_array);
  467. if (g_queue_get_length(ud->st) == 0) {
  468. ud->parser_state = read_param_element;
  469. }
  470. else {
  471. last_queued = GPOINTER_TO_INT(g_queue_peek_head(ud->st));
  472. if (last_queued == st_struct) {
  473. ud->parser_state = read_struct_element;
  474. }
  475. else {
  476. ud->parser_state = read_array_element;
  477. }
  478. }
  479. msg_debug_xmlrpc("pop array");
  480. }
  481. else {
  482. /* Error state */
  483. ud->parser_state = error_state;
  484. }
  485. break;
  486. case read_array_value:
  487. /* Got tag data */
  488. if (g_ascii_strcasecmp(name, "data") == 0) {
  489. ud->parser_state = read_array;
  490. }
  491. else {
  492. /* Error state */
  493. ud->parser_state = error_state;
  494. }
  495. break;
  496. case read_array_element:
  497. /* Got tag value */
  498. if (g_ascii_strcasecmp(name, "value") == 0) {
  499. unsigned int tbl_len = rspamd_lua_table_size(ud->L, -2);
  500. lua_rawseti(ud->L, -2, tbl_len + 1);
  501. msg_debug_xmlrpc("set array element idx: %d", tbl_len + 1);
  502. ud->parser_state = read_array_value;
  503. }
  504. else {
  505. /* Error state */
  506. ud->parser_state = error_state;
  507. }
  508. break;
  509. default:
  510. break;
  511. }
  512. msg_debug_xmlrpc("switched state on end tag %d->%d",
  513. last_state, ud->parser_state);
  514. if (ud->parser_state == error_state) {
  515. g_set_error(error,
  516. xmlrpc_error_quark(), 1, "xmlrpc parse error on state: %d, while parsing end tag: %s",
  517. last_state, name);
  518. }
  519. }
  520. static void
  521. xmlrpc_text(GMarkupParseContext *context,
  522. const char *text,
  523. gsize text_len,
  524. gpointer user_data,
  525. GError **error)
  526. {
  527. struct lua_xmlrpc_ud *ud = user_data;
  528. gulong num;
  529. double dnum;
  530. /* Strip line */
  531. while (text_len > 0 && g_ascii_isspace(*text)) {
  532. text++;
  533. text_len--;
  534. }
  535. while (text_len > 0 && g_ascii_isspace(text[text_len - 1])) {
  536. text_len--;
  537. }
  538. if (text_len > 0) {
  539. msg_debug_xmlrpc("got data on state %d", ud->parser_state);
  540. switch (ud->parser_state) {
  541. case read_struct_member_value:
  542. /* Push key */
  543. lua_pushlstring(ud->L, text, text_len);
  544. break;
  545. case read_string:
  546. /* Push string value */
  547. lua_pushlstring(ud->L, text, text_len);
  548. break;
  549. case read_int:
  550. /* Push integer value */
  551. rspamd_strtoul(text, text_len, &num);
  552. lua_pushinteger(ud->L, num);
  553. break;
  554. case read_double:
  555. /* Push integer value */
  556. dnum = strtod(text, NULL);
  557. lua_pushnumber(ud->L, dnum);
  558. break;
  559. default:
  560. break;
  561. }
  562. ud->got_text = TRUE;
  563. }
  564. }
  565. static void
  566. xmlrpc_error(GMarkupParseContext *context, GError *error, gpointer user_data)
  567. {
  568. msg_err("xmlrpc parser error: %s", error->message);
  569. }
  570. static int
  571. lua_xmlrpc_parse_reply(lua_State *L)
  572. {
  573. LUA_TRACE_POINT;
  574. const char *data;
  575. GMarkupParseContext *ctx;
  576. GError *err = NULL;
  577. struct lua_xmlrpc_ud ud;
  578. gsize s;
  579. gboolean res;
  580. data = luaL_checklstring(L, 1, &s);
  581. if (data != NULL) {
  582. ud.L = L;
  583. ud.parser_state = read_method_response;
  584. ud.param_count = 0;
  585. ud.st = g_queue_new();
  586. ctx = g_markup_parse_context_new(&xmlrpc_parser,
  587. G_MARKUP_TREAT_CDATA_AS_TEXT, &ud, NULL);
  588. res = g_markup_parse_context_parse(ctx, data, s, &err);
  589. g_markup_parse_context_free(ctx);
  590. if (!res) {
  591. lua_pushnil(L);
  592. }
  593. }
  594. else {
  595. lua_pushnil(L);
  596. }
  597. /* Return table or nil */
  598. return 1;
  599. }
  600. static int
  601. lua_xmlrpc_parse_table(lua_State *L,
  602. int pos,
  603. char *databuf,
  604. int pr,
  605. gsize size)
  606. {
  607. int r = pr, num;
  608. double dnum;
  609. r += rspamd_snprintf(databuf + r, size - r, "<struct>");
  610. lua_pushnil(L); /* first key */
  611. while (lua_next(L, pos) != 0) {
  612. /* uses 'key' (at index -2) and 'value' (at index -1) */
  613. if (lua_type(L, -2) != LUA_TSTRING) {
  614. /* Ignore non sting keys */
  615. lua_pop(L, 1);
  616. continue;
  617. }
  618. r += rspamd_snprintf(databuf + r,
  619. size - r,
  620. "<member><name>%s</name><value>",
  621. lua_tostring(L, -2));
  622. switch (lua_type(L, -1)) {
  623. case LUA_TNUMBER:
  624. num = lua_tointeger(L, -1);
  625. dnum = lua_tonumber(L, -1);
  626. /* Try to avoid conversion errors */
  627. if (dnum != (double) num) {
  628. r += rspamd_snprintf(databuf + r,
  629. sizeof(databuf) - r,
  630. "<double>%f</double>",
  631. dnum);
  632. }
  633. else {
  634. r += rspamd_snprintf(databuf + r,
  635. sizeof(databuf) - r,
  636. "<int>%d</int>",
  637. num);
  638. }
  639. break;
  640. case LUA_TBOOLEAN:
  641. r += rspamd_snprintf(databuf + r,
  642. size - r,
  643. "<boolean>%d</boolean>",
  644. lua_toboolean(L, -1) ? 1 : 0);
  645. break;
  646. case LUA_TSTRING:
  647. r += rspamd_snprintf(databuf + r, size - r, "<string>%s</string>",
  648. lua_tostring(L, -1));
  649. break;
  650. case LUA_TTABLE:
  651. /* Recursive call */
  652. r += lua_xmlrpc_parse_table(L, -1, databuf + r, r, size);
  653. break;
  654. }
  655. r += rspamd_snprintf(databuf + r, size - r, "</value></member>");
  656. /* removes 'value'; keeps 'key' for next iteration */
  657. lua_pop(L, 1);
  658. }
  659. r += rspamd_snprintf(databuf + r, size - r, "</struct>");
  660. return r - pr;
  661. }
  662. /*
  663. * Internal limitation: xmlrpc request must NOT be more than
  664. * BUFSIZ * 2 (16384 bytes)
  665. */
  666. static int
  667. lua_xmlrpc_make_request(lua_State *L)
  668. {
  669. LUA_TRACE_POINT;
  670. char databuf[BUFSIZ * 2];
  671. const char *func;
  672. int r, top, i, num;
  673. double dnum;
  674. func = luaL_checkstring(L, 1);
  675. if (func) {
  676. r = rspamd_snprintf(databuf, sizeof(databuf),
  677. "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
  678. "<methodCall><methodName>%s</methodName><params>",
  679. func);
  680. /* Extract arguments */
  681. top = lua_gettop(L);
  682. /* Get additional options */
  683. for (i = 2; i <= top; i++) {
  684. r += rspamd_snprintf(databuf + r,
  685. sizeof(databuf) - r,
  686. "<param><value>");
  687. switch (lua_type(L, i)) {
  688. case LUA_TNUMBER:
  689. num = lua_tointeger(L, i);
  690. dnum = lua_tonumber(L, i);
  691. /* Try to avoid conversion errors */
  692. if (dnum != (double) num) {
  693. r += rspamd_snprintf(databuf + r,
  694. sizeof(databuf) - r,
  695. "<double>%f</double>",
  696. dnum);
  697. }
  698. else {
  699. r += rspamd_snprintf(databuf + r,
  700. sizeof(databuf) - r,
  701. "<int>%d</int>",
  702. num);
  703. }
  704. break;
  705. case LUA_TBOOLEAN:
  706. r += rspamd_snprintf(databuf + r,
  707. sizeof(databuf) - r,
  708. "<boolean>%d</boolean>",
  709. lua_toboolean(L, i) ? 1 : 0);
  710. break;
  711. case LUA_TSTRING:
  712. r += rspamd_snprintf(databuf + r,
  713. sizeof(databuf) - r,
  714. "<string>%s</string>",
  715. lua_tostring(L, i));
  716. break;
  717. case LUA_TTABLE:
  718. r +=
  719. lua_xmlrpc_parse_table(L, i, databuf, r, sizeof(databuf));
  720. break;
  721. }
  722. r += rspamd_snprintf(databuf + r,
  723. sizeof(databuf) - r,
  724. "</value></param>");
  725. }
  726. r += rspamd_snprintf(databuf + r,
  727. sizeof(databuf) - r,
  728. "</params></methodCall>");
  729. lua_pushlstring(L, databuf, r);
  730. }
  731. else {
  732. lua_pushnil(L);
  733. }
  734. return 1;
  735. }
  736. static int
  737. lua_load_xmlrpc(lua_State *L)
  738. {
  739. lua_newtable(L);
  740. luaL_register(L, NULL, xmlrpclib_m);
  741. return 1;
  742. }
  743. void luaopen_xmlrpc(lua_State *L)
  744. {
  745. rspamd_lua_add_preload(L, "rspamd_xmlrpc", lua_load_xmlrpc);
  746. }