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

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