xmlrpc_client.c 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983
  1. /* Copyright (C) 2001 by First Peer, Inc. All rights reserved.
  2. **
  3. ** Redistribution and use in source and binary forms, with or without
  4. ** modification, are permitted provided that the following conditions
  5. ** are met:
  6. ** 1. Redistributions of source code must retain the above copyright
  7. ** notice, this list of conditions and the following disclaimer.
  8. ** 2. Redistributions in binary form must reproduce the above copyright
  9. ** notice, this list of conditions and the following disclaimer in the
  10. ** documentation and/or other materials provided with the distribution.
  11. ** 3. The name of the author may not be used to endorse or promote products
  12. ** derived from this software without specific prior written permission.
  13. **
  14. ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  15. ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16. ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  17. ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  18. ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  19. ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  20. ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  21. ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  22. ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  23. ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  24. ** SUCH DAMAGE. */
  25. #include "xmlrpc_config.h"
  26. #undef PACKAGE
  27. #undef VERSION
  28. #include <stddef.h>
  29. #include <stdio.h>
  30. #include <string.h>
  31. #include <stdlib.h>
  32. #include <assert.h>
  33. #include <errno.h>
  34. #include "bool.h"
  35. #include "mallocvar.h"
  36. #include "xmlrpc.h"
  37. #include "xmlrpc_int.h"
  38. #include "xmlrpc_client.h"
  39. #include "xmlrpc_client_int.h"
  40. /* transport_config.h defines XMLRPC_DEFAULT_TRANSPORT,
  41. MUST_BUILD_WININET_CLIENT, MUST_BUILD_CURL_CLIENT,
  42. MUST_BUILD_LIBWWW_CLIENT
  43. */
  44. #include "transport_config.h"
  45. #if MUST_BUILD_WININET_CLIENT
  46. #include "xmlrpc_wininet_transport.h"
  47. #endif
  48. #if MUST_BUILD_CURL_CLIENT
  49. #include "xmlrpc_curl_transport.h"
  50. #endif
  51. #if MUST_BUILD_LIBWWW_CLIENT
  52. #include "xmlrpc_libwww_transport.h"
  53. #endif
  54. struct xmlrpc_client {
  55. /*----------------------------------------------------------------------------
  56. This represents a client object.
  57. -----------------------------------------------------------------------------*/
  58. struct clientTransport * transportP;
  59. };
  60. typedef struct call_info
  61. {
  62. /* These fields are used when performing asynchronous calls.
  63. ** The _asynch_data_holder contains server_url, method_name and
  64. ** param_array, so it's the only thing we need to free. */
  65. xmlrpc_value *_asynch_data_holder;
  66. char *server_url;
  67. char *method_name;
  68. xmlrpc_value *param_array;
  69. xmlrpc_response_handler callback;
  70. void *user_data;
  71. /* The serialized XML data passed to this call. We keep this around
  72. ** for use by our source_anchor field. */
  73. xmlrpc_mem_block *serialized_xml;
  74. } call_info;
  75. static bool clientInitialized = FALSE;
  76. /*=========================================================================
  77. ** Initialization and Shutdown
  78. **=========================================================================
  79. */
  80. static struct clientTransportOps clientTransportOps;
  81. static struct xmlrpc_client client;
  82. /* Some day, we need to make this dynamically allocated, so there can
  83. be more than one client per program and just generally to provide
  84. a cleaner interface.
  85. */
  86. extern void
  87. xmlrpc_client_init(int const flags,
  88. const char * const appname,
  89. const char * const appversion) {
  90. struct xmlrpc_clientparms clientparms;
  91. /* As our interface does not allow for failure, we just fail silently ! */
  92. xmlrpc_env env;
  93. xmlrpc_env_init(&env);
  94. clientparms.transport = XMLRPC_DEFAULT_TRANSPORT;
  95. xmlrpc_client_init2(&env, flags,
  96. appname, appversion,
  97. &clientparms, XMLRPC_CPSIZE(transport));
  98. xmlrpc_env_clean(&env);
  99. }
  100. const char *
  101. xmlrpc_client_get_default_transport(xmlrpc_env * const env ATTR_UNUSED) {
  102. return XMLRPC_DEFAULT_TRANSPORT;
  103. }
  104. static void
  105. setupTransport(xmlrpc_env * const envP,
  106. const char * const transportName) {
  107. if (FALSE) {
  108. }
  109. #if MUST_BUILD_WININET_CLIENT
  110. else if (strcmp(transportName, "wininet") == 0)
  111. clientTransportOps = xmlrpc_wininet_transport_ops;
  112. #endif
  113. #if MUST_BUILD_CURL_CLIENT
  114. else if (strcmp(transportName, "curl") == 0)
  115. clientTransportOps = xmlrpc_curl_transport_ops;
  116. else if (strcmp(transportName, "libcurl") == 0)
  117. clientTransportOps = xmlrpc_curl_transport_ops;
  118. #endif
  119. #if MUST_BUILD_LIBWWW_CLIENT
  120. else if (strcmp(transportName, "libwww") == 0)
  121. clientTransportOps = xmlrpc_libwww_transport_ops;
  122. #endif
  123. else
  124. xmlrpc_env_set_fault_formatted(
  125. envP, XMLRPC_INTERNAL_ERROR,
  126. "Unrecognized XML transport name '%s'", transportName);
  127. }
  128. void
  129. xmlrpc_client_init2(xmlrpc_env * const envP,
  130. int const flags,
  131. const char * const appname,
  132. const char * const appversion,
  133. struct xmlrpc_clientparms * const clientparmsP,
  134. unsigned int const parm_size) {
  135. if (clientInitialized)
  136. xmlrpc_env_set_fault_formatted(
  137. envP, XMLRPC_INTERNAL_ERROR,
  138. "Xmlrpc-c client instance has already been initialized "
  139. "(need to call xmlrpc_client_cleanup() before you can "
  140. "reinitialize).");
  141. else {
  142. const char * transportName;
  143. if (parm_size < XMLRPC_CPSIZE(transport) ||
  144. clientparmsP->transport == NULL) {
  145. /* He didn't specify a transport. Use the default */
  146. transportName = xmlrpc_client_get_default_transport(envP);
  147. } else
  148. transportName = clientparmsP->transport;
  149. if (!envP->fault_occurred) {
  150. setupTransport(envP, transportName);
  151. if (!envP->fault_occurred) {
  152. clientTransportOps.create(envP, flags, appname, appversion,
  153. &client.transportP);
  154. if (!envP->fault_occurred)
  155. clientInitialized = TRUE;
  156. }
  157. }
  158. }
  159. }
  160. void
  161. xmlrpc_client_cleanup() {
  162. XMLRPC_ASSERT(clientInitialized);
  163. clientTransportOps.destroy(client.transportP);
  164. clientInitialized = FALSE;
  165. }
  166. static void
  167. call_info_free(call_info * const callInfoP) {
  168. /* Assume the worst.. That only parts of the call_info are valid. */
  169. XMLRPC_ASSERT_PTR_OK(callInfoP);
  170. /* If this has been allocated, we're responsible for destroying it. */
  171. if (callInfoP->_asynch_data_holder)
  172. xmlrpc_DECREF(callInfoP->_asynch_data_holder);
  173. /* Now we can blow away the XML data. */
  174. if (callInfoP->serialized_xml)
  175. xmlrpc_mem_block_free(callInfoP->serialized_xml);
  176. free(callInfoP);
  177. }
  178. static void
  179. call_info_new(xmlrpc_env * const envP,
  180. xmlrpc_server_info * const server,
  181. const char * const method_name,
  182. xmlrpc_value * const argP,
  183. call_info ** const callInfoPP) {
  184. /*----------------------------------------------------------------------------
  185. Create a call_info object. A call_info object represents an XML-RPC
  186. call.
  187. -----------------------------------------------------------------------------*/
  188. call_info * callInfoP;
  189. XMLRPC_ASSERT_PTR_OK(argP);
  190. XMLRPC_ASSERT_PTR_OK(callInfoPP);
  191. if (method_name == NULL)
  192. xmlrpc_env_set_fault_formatted(
  193. envP, XMLRPC_INTERNAL_ERROR,
  194. "method name argument is NULL pointer");
  195. else if (server == NULL)
  196. xmlrpc_env_set_fault_formatted(
  197. envP, XMLRPC_INTERNAL_ERROR,
  198. "server info argument is NULL pointer");
  199. else {
  200. MALLOCVAR(callInfoP);
  201. if (callInfoP == NULL)
  202. xmlrpc_env_set_fault_formatted(
  203. envP, XMLRPC_INTERNAL_ERROR,
  204. "Couldn't allocate memory for xmlrpc_call_info");
  205. else {
  206. xmlrpc_mem_block * callXmlP;
  207. /* Clear contents. */
  208. memset(callInfoP, 0, sizeof(*callInfoP));
  209. /* Make the XML for our call */
  210. callXmlP = XMLRPC_MEMBLOCK_NEW(char, envP, 0);
  211. if (!envP->fault_occurred) {
  212. xmlrpc_serialize_call(envP, callXmlP, method_name, argP);
  213. if (!envP->fault_occurred) {
  214. xmlrpc_traceXml("XML-RPC CALL",
  215. XMLRPC_MEMBLOCK_CONTENTS(char, callXmlP),
  216. XMLRPC_MEMBLOCK_SIZE(char, callXmlP));
  217. callInfoP->serialized_xml = callXmlP;
  218. *callInfoPP = callInfoP;
  219. }
  220. if (envP->fault_occurred)
  221. XMLRPC_MEMBLOCK_FREE(char, callXmlP);
  222. }
  223. if (envP->fault_occurred)
  224. free(callInfoP);
  225. }
  226. }
  227. }
  228. static void
  229. clientCallServerParams(xmlrpc_env * const envP,
  230. struct clientTransport * const transportP,
  231. xmlrpc_server_info * const serverP,
  232. const char * const methodName,
  233. xmlrpc_value * const paramArrayP,
  234. xmlrpc_value ** const resultPP) {
  235. call_info * callInfoP;
  236. if (!clientInitialized)
  237. xmlrpc_env_set_fault_formatted(
  238. envP, XMLRPC_INTERNAL_ERROR,
  239. "Xmlrpc-c client instance has not been initialized "
  240. "(need to call xmlrpc_client_init2()).");
  241. else {
  242. call_info_new(envP, serverP, methodName, paramArrayP, &callInfoP);
  243. if (!envP->fault_occurred) {
  244. xmlrpc_mem_block * respXmlP;
  245. clientTransportOps.call(envP, transportP, serverP,
  246. callInfoP->serialized_xml, callInfoP,
  247. &respXmlP);
  248. if (!envP->fault_occurred) {
  249. xmlrpc_traceXml("XML-RPC RESPONSE",
  250. XMLRPC_MEMBLOCK_CONTENTS(char, respXmlP),
  251. XMLRPC_MEMBLOCK_SIZE(char, respXmlP));
  252. *resultPP = xmlrpc_parse_response(
  253. envP,
  254. XMLRPC_MEMBLOCK_CONTENTS(char, respXmlP),
  255. XMLRPC_MEMBLOCK_SIZE(char, respXmlP));
  256. XMLRPC_MEMBLOCK_FREE(char, respXmlP);
  257. }
  258. call_info_free(callInfoP);
  259. }
  260. }
  261. }
  262. xmlrpc_value *
  263. xmlrpc_client_call_params(xmlrpc_env * const envP,
  264. const char * const serverUrl,
  265. const char * const methodName,
  266. xmlrpc_value * const paramArrayP) {
  267. xmlrpc_value *retval;
  268. XMLRPC_ASSERT_ENV_OK(envP);
  269. XMLRPC_ASSERT_PTR_OK(serverUrl);
  270. if (!clientInitialized)
  271. xmlrpc_env_set_fault_formatted(
  272. envP, XMLRPC_INTERNAL_ERROR,
  273. "Xmlrpc-c client instance has not been initialized "
  274. "(need to call xmlrpc_client_init2()).");
  275. else {
  276. xmlrpc_server_info * serverP;
  277. /* Build a server info object and make our call. */
  278. serverP = xmlrpc_server_info_new(envP, serverUrl);
  279. if (!envP->fault_occurred) {
  280. clientCallServerParams(envP, client.transportP, serverP,
  281. methodName, paramArrayP,
  282. &retval);
  283. xmlrpc_server_info_free(serverP);
  284. }
  285. }
  286. if (!envP->fault_occurred)
  287. XMLRPC_ASSERT_VALUE_OK(retval);
  288. return retval;
  289. }
  290. static xmlrpc_value *
  291. xmlrpc_client_call_va(xmlrpc_env * const envP,
  292. const char * const server_url,
  293. const char * const method_name,
  294. const char * const format,
  295. va_list args) {
  296. xmlrpc_value * argP;
  297. xmlrpc_value * retval;
  298. xmlrpc_env argenv;
  299. const char * suffix;
  300. XMLRPC_ASSERT_ENV_OK(envP);
  301. XMLRPC_ASSERT_PTR_OK(format);
  302. /* Build our argument value. */
  303. xmlrpc_env_init(&argenv);
  304. xmlrpc_build_value_va(&argenv, format, args, &argP, &suffix);
  305. if (argenv.fault_occurred) {
  306. xmlrpc_env_set_fault_formatted(
  307. envP, argenv.fault_code, "Invalid RPC arguments. "
  308. "The format argument must indicate a single array, and the "
  309. "following arguments must correspond to that format argument. "
  310. "The failure is: %s",
  311. argenv.fault_string);
  312. xmlrpc_env_clean(&argenv);
  313. } else {
  314. XMLRPC_ASSERT_VALUE_OK(argP);
  315. if (*suffix != '\0')
  316. xmlrpc_env_set_fault_formatted(
  317. envP, XMLRPC_INTERNAL_ERROR, "Junk after the argument "
  318. "specifier: '%s'. There must be exactly one arument.",
  319. suffix);
  320. else {
  321. /* Perform the actual XML-RPC call. */
  322. retval = xmlrpc_client_call_params(
  323. envP, server_url, method_name, argP);
  324. if (!envP->fault_occurred)
  325. XMLRPC_ASSERT_VALUE_OK(retval);
  326. }
  327. xmlrpc_DECREF(argP);
  328. }
  329. return retval;
  330. }
  331. xmlrpc_value *
  332. xmlrpc_client_call(xmlrpc_env * const envP,
  333. const char * const server_url,
  334. const char * const method_name,
  335. const char * const format,
  336. ...) {
  337. xmlrpc_value * result;
  338. va_list args;
  339. va_start(args, format);
  340. result = xmlrpc_client_call_va(envP, server_url,
  341. method_name, format, args);
  342. va_end(args);
  343. return result;
  344. }
  345. xmlrpc_value *
  346. xmlrpc_client_call_server(xmlrpc_env * const envP,
  347. xmlrpc_server_info * const serverP,
  348. const char * const methodName,
  349. const char * const format,
  350. ...) {
  351. va_list args;
  352. xmlrpc_value * paramArrayP;
  353. xmlrpc_value * retval;
  354. const char * suffix;
  355. XMLRPC_ASSERT_ENV_OK(envP);
  356. XMLRPC_ASSERT_PTR_OK(format);
  357. /* Build our argument */
  358. va_start(args, format);
  359. xmlrpc_build_value_va(envP, format, args, &paramArrayP, &suffix);
  360. va_end(args);
  361. if (!envP->fault_occurred) {
  362. if (*suffix != '\0')
  363. xmlrpc_env_set_fault_formatted(
  364. envP, XMLRPC_INTERNAL_ERROR, "Junk after the argument "
  365. "specifier: '%s'. There must be exactly one arument.",
  366. suffix);
  367. else
  368. clientCallServerParams(envP, client.transportP, serverP,
  369. methodName, paramArrayP,
  370. &retval);
  371. xmlrpc_DECREF(paramArrayP);
  372. }
  373. return retval;
  374. }
  375. void
  376. xmlrpc_client_event_loop_finish_asynch(void) {
  377. XMLRPC_ASSERT(clientInitialized);
  378. clientTransportOps.finish_asynch(client.transportP, timeout_no, 0);
  379. }
  380. void
  381. xmlrpc_client_event_loop_finish_asynch_timeout(timeout_t const timeout) {
  382. XMLRPC_ASSERT(clientInitialized);
  383. clientTransportOps.finish_asynch(client.transportP, timeout_yes, timeout);
  384. }
  385. static void
  386. call_info_set_asynch_data(xmlrpc_env * const env,
  387. call_info * const info,
  388. const char * const server_url,
  389. const char * const method_name,
  390. xmlrpc_value * const argP,
  391. xmlrpc_response_handler callback,
  392. void * const user_data) {
  393. xmlrpc_value *holder;
  394. /* Error-handling preconditions. */
  395. holder = NULL;
  396. XMLRPC_ASSERT_ENV_OK(env);
  397. XMLRPC_ASSERT_PTR_OK(info);
  398. XMLRPC_ASSERT(info->_asynch_data_holder == NULL);
  399. XMLRPC_ASSERT_PTR_OK(server_url);
  400. XMLRPC_ASSERT_PTR_OK(method_name);
  401. XMLRPC_ASSERT_VALUE_OK(argP);
  402. /* Install our callback and user_data.
  403. ** (We're not responsible for destroying the user_data.) */
  404. info->callback = callback;
  405. info->user_data = user_data;
  406. /* Build an XML-RPC data structure to hold our other data. This makes
  407. ** copies of server_url and method_name, and increments the reference
  408. ** to the argument *argP. */
  409. holder = xmlrpc_build_value(env, "(ssV)",
  410. server_url, method_name, argP);
  411. XMLRPC_FAIL_IF_FAULT(env);
  412. /* Parse the newly-allocated structure into our public member variables.
  413. ** This doesn't make any new references, so we can dispose of the whole
  414. ** thing by DECREF'ing the one master reference. Nifty, huh? */
  415. xmlrpc_parse_value(env, holder, "(ssV)",
  416. &info->server_url,
  417. &info->method_name,
  418. &info->param_array);
  419. XMLRPC_FAIL_IF_FAULT(env);
  420. /* Hand over ownership of the holder to the call_info struct. */
  421. info->_asynch_data_holder = holder;
  422. holder = NULL;
  423. cleanup:
  424. if (env->fault_occurred) {
  425. if (holder)
  426. xmlrpc_DECREF(holder);
  427. }
  428. }
  429. /*=========================================================================
  430. ** xmlrpc_server_info
  431. **=========================================================================
  432. */
  433. xmlrpc_server_info *
  434. xmlrpc_server_info_new (xmlrpc_env * const env,
  435. const char * const server_url) {
  436. xmlrpc_server_info *server;
  437. char *url_copy;
  438. /* Error-handling preconditions. */
  439. server = NULL;
  440. url_copy = NULL;
  441. XMLRPC_ASSERT_ENV_OK(env);
  442. XMLRPC_ASSERT_PTR_OK(server_url);
  443. /* Allocate our memory blocks. */
  444. server = (xmlrpc_server_info*) malloc(sizeof(xmlrpc_server_info));
  445. XMLRPC_FAIL_IF_NULL(server, env, XMLRPC_INTERNAL_ERROR,
  446. "Couldn't allocate memory for xmlrpc_server_info");
  447. memset(server, 0, sizeof(xmlrpc_server_info));
  448. url_copy = (char*) malloc(strlen(server_url) + 1);
  449. XMLRPC_FAIL_IF_NULL(url_copy, env, XMLRPC_INTERNAL_ERROR,
  450. "Couldn't allocate memory for server URL");
  451. /* Build our object. */
  452. strcpy(url_copy, server_url);
  453. server->_server_url = url_copy;
  454. server->_http_basic_auth = NULL;
  455. cleanup:
  456. if (env->fault_occurred) {
  457. if (url_copy)
  458. free(url_copy);
  459. if (server)
  460. free(server);
  461. return NULL;
  462. }
  463. return server;
  464. }
  465. xmlrpc_server_info * xmlrpc_server_info_copy(xmlrpc_env *env,
  466. xmlrpc_server_info *aserver)
  467. {
  468. xmlrpc_server_info *server;
  469. char *url_copy, *auth_copy;
  470. XMLRPC_ASSERT_ENV_OK(env);
  471. XMLRPC_ASSERT_PTR_OK(aserver);
  472. /* Error-handling preconditions. */
  473. server = NULL;
  474. url_copy = NULL;
  475. auth_copy = NULL;
  476. /* Allocate our memory blocks. */
  477. server = (xmlrpc_server_info*) malloc(sizeof(xmlrpc_server_info));
  478. XMLRPC_FAIL_IF_NULL(server, env, XMLRPC_INTERNAL_ERROR,
  479. "Couldn't allocate memory for xmlrpc_server_info");
  480. url_copy = (char*) malloc(strlen(aserver->_server_url) + 1);
  481. XMLRPC_FAIL_IF_NULL(url_copy, env, XMLRPC_INTERNAL_ERROR,
  482. "Couldn't allocate memory for server URL");
  483. auth_copy = (char*) malloc(strlen(aserver->_http_basic_auth) + 1);
  484. XMLRPC_FAIL_IF_NULL(auth_copy, env, XMLRPC_INTERNAL_ERROR,
  485. "Couldn't allocate memory for authentication info");
  486. /* Build our object. */
  487. strcpy(url_copy, aserver->_server_url);
  488. server->_server_url = url_copy;
  489. strcpy(auth_copy, aserver->_http_basic_auth);
  490. server->_http_basic_auth = auth_copy;
  491. cleanup:
  492. if (env->fault_occurred) {
  493. if (url_copy)
  494. free(url_copy);
  495. if (auth_copy)
  496. free(auth_copy);
  497. if (server)
  498. free(server);
  499. return NULL;
  500. }
  501. return server;
  502. }
  503. void xmlrpc_server_info_free (xmlrpc_server_info *server)
  504. {
  505. XMLRPC_ASSERT_PTR_OK(server);
  506. XMLRPC_ASSERT(server->_server_url != XMLRPC_BAD_POINTER);
  507. if (server->_http_basic_auth)
  508. free(server->_http_basic_auth);
  509. free(server->_server_url);
  510. server->_server_url = XMLRPC_BAD_POINTER;
  511. free(server);
  512. }
  513. /*=========================================================================
  514. ** xmlrpc_client_call_asynch
  515. **=========================================================================
  516. */
  517. void
  518. xmlrpc_client_call_asynch(const char * const serverUrl,
  519. const char * const methodName,
  520. xmlrpc_response_handler callback,
  521. void * const userData,
  522. const char * const format,
  523. ...) {
  524. xmlrpc_env env;
  525. va_list args;
  526. xmlrpc_value * paramArrayP;
  527. const char * suffix;
  528. xmlrpc_env_init(&env);
  529. XMLRPC_ASSERT_PTR_OK(serverUrl);
  530. XMLRPC_ASSERT_PTR_OK(format);
  531. /* Build our argument array. */
  532. va_start(args, format);
  533. xmlrpc_build_value_va(&env, format, args, &paramArrayP, &suffix);
  534. va_end(args);
  535. if (env.fault_occurred) {
  536. /* Unfortunately, we have no way to return an error and the
  537. regular callback for a failed RPC is designed to have the
  538. parameter array passed to it. This was probably an oversight
  539. of the original asynch design, but now we have to be as
  540. backward compatible as possible, so we do this:
  541. */
  542. (*callback)(serverUrl, methodName, NULL, userData, &env, NULL);
  543. } else {
  544. if (*suffix != '\0')
  545. xmlrpc_env_set_fault_formatted(
  546. &env, XMLRPC_INTERNAL_ERROR, "Junk after the argument "
  547. "specifier: '%s'. There must be exactly one arument.",
  548. suffix);
  549. else {
  550. xmlrpc_server_info * serverP;
  551. serverP = xmlrpc_server_info_new(&env, serverUrl);
  552. if (!env.fault_occurred) {
  553. xmlrpc_client_call_server_asynch_params(
  554. serverP, methodName, callback, userData,
  555. paramArrayP);
  556. }
  557. xmlrpc_server_info_free(serverP);
  558. }
  559. if (env.fault_occurred)
  560. (*callback)(serverUrl, methodName, paramArrayP, userData,
  561. &env, NULL);
  562. xmlrpc_DECREF(paramArrayP);
  563. }
  564. xmlrpc_env_clean(&env);
  565. }
  566. void
  567. xmlrpc_client_call_asynch_params(const char * const serverUrl,
  568. const char * const methodName,
  569. xmlrpc_response_handler callback,
  570. void * const userData,
  571. xmlrpc_value * const paramArrayP) {
  572. xmlrpc_env env;
  573. xmlrpc_server_info *serverP;
  574. xmlrpc_env_init(&env);
  575. XMLRPC_ASSERT_PTR_OK(serverUrl);
  576. serverP = xmlrpc_server_info_new(&env, serverUrl);
  577. if (!env.fault_occurred) {
  578. xmlrpc_client_call_server_asynch_params(
  579. serverP, methodName, callback, userData, paramArrayP);
  580. xmlrpc_server_info_free(serverP);
  581. }
  582. if (env.fault_occurred)
  583. /* We have no way to return failure; we report the failure
  584. as it happened after we successfully started the RPC.
  585. */
  586. (*callback)(serverUrl, methodName, paramArrayP, userData,
  587. &env, NULL);
  588. xmlrpc_env_clean(&env);
  589. }
  590. void
  591. xmlrpc_client_call_server_asynch(xmlrpc_server_info * const serverP,
  592. const char * const methodName,
  593. xmlrpc_response_handler callback,
  594. void * const userData,
  595. const char * const format,
  596. ...) {
  597. xmlrpc_env env;
  598. va_list args;
  599. xmlrpc_value * paramArrayP;
  600. const char * suffix;
  601. xmlrpc_env_init(&env);
  602. XMLRPC_ASSERT_PTR_OK(format);
  603. /* Build our parameter array. */
  604. va_start(args, format);
  605. xmlrpc_build_value_va(&env, format, args, &paramArrayP, &suffix);
  606. va_end(args);
  607. if (env.fault_occurred) {
  608. /* Unfortunately, we have no way to return an error and the
  609. regular callback for a failed RPC is designed to have the
  610. parameter array passed to it. This was probably an oversight
  611. of the original asynch design, but now we have to be as
  612. backward compatible as possible, so we do this:
  613. */
  614. (*callback)(serverP->_server_url, methodName, NULL, userData,
  615. &env, NULL);
  616. } else {
  617. if (*suffix != '\0')
  618. xmlrpc_env_set_fault_formatted(
  619. &env, XMLRPC_INTERNAL_ERROR, "Junk after the argument "
  620. "specifier: '%s'. There must be exactly one arument.",
  621. suffix);
  622. else {
  623. xmlrpc_client_call_server_asynch_params(
  624. serverP, methodName, callback, userData, paramArrayP);
  625. }
  626. xmlrpc_DECREF(paramArrayP);
  627. }
  628. if (env.fault_occurred)
  629. (*callback)(serverP->_server_url, methodName, paramArrayP, userData,
  630. &env, NULL);
  631. xmlrpc_env_clean(&env);
  632. }
  633. static void
  634. asynchComplete(call_info * const callInfoP,
  635. xmlrpc_mem_block * const responseXmlP,
  636. xmlrpc_env const transportEnv) {
  637. /*----------------------------------------------------------------------------
  638. Complete an asynchronous XML-RPC call request.
  639. This includes calling the user's RPC completion routine.
  640. 'transportEnv' describes the an error that the transport
  641. encountered in processing the call. If the transport successfully
  642. sent the call to the server and processed the response but the
  643. server failed the call, 'transportEnv' indicates no error, and the
  644. response in *callInfoP might very well indicate that the server
  645. failed the request.
  646. -----------------------------------------------------------------------------*/
  647. xmlrpc_env env;
  648. xmlrpc_value * responseP;
  649. xmlrpc_env_init(&env);
  650. if (transportEnv.fault_occurred)
  651. xmlrpc_env_set_fault_formatted(
  652. &env, transportEnv.fault_code,
  653. "Client transport failed to execute the RPC. %s",
  654. transportEnv.fault_string);
  655. if (!env.fault_occurred)
  656. responseP = xmlrpc_parse_response(
  657. &env,
  658. XMLRPC_MEMBLOCK_CONTENTS(char, responseXmlP),
  659. XMLRPC_MEMBLOCK_SIZE(char, responseXmlP));
  660. /* Call the user's callback function with the result */
  661. (*callInfoP->callback)(callInfoP->server_url,
  662. callInfoP->method_name,
  663. callInfoP->param_array,
  664. callInfoP->user_data, &env, responseP);
  665. if (!env.fault_occurred)
  666. xmlrpc_DECREF(responseP);
  667. call_info_free(callInfoP);
  668. xmlrpc_env_clean(&env);
  669. }
  670. static void
  671. sendRequest(xmlrpc_env * const envP,
  672. struct clientTransport * const transportP,
  673. xmlrpc_server_info * const serverP,
  674. const char * const methodName,
  675. xmlrpc_response_handler responseHandler,
  676. void * const userData,
  677. xmlrpc_value * const argP) {
  678. call_info * callInfoP;
  679. call_info_new(envP, serverP, methodName, argP, &callInfoP);
  680. if (!envP->fault_occurred) {
  681. call_info_set_asynch_data(envP, callInfoP,
  682. serverP->_server_url, methodName,
  683. argP, responseHandler, userData);
  684. if (!envP->fault_occurred)
  685. clientTransportOps.send_request(
  686. envP, transportP, serverP, callInfoP->serialized_xml,
  687. &asynchComplete, callInfoP);
  688. if (envP->fault_occurred)
  689. call_info_free(callInfoP);
  690. else {
  691. /* asynchComplete() will free *callInfoP */
  692. }
  693. }
  694. if (envP->fault_occurred) {
  695. /* Transport did not start the call. Report the call complete
  696. (with error) now.
  697. */
  698. (*responseHandler)(serverP->_server_url, methodName, argP, userData,
  699. envP, NULL);
  700. } else {
  701. /* The transport will call *responseHandler() when it has completed
  702. the call
  703. */
  704. }
  705. }
  706. void
  707. xmlrpc_client_call_server_asynch_params(
  708. xmlrpc_server_info * const serverP,
  709. const char * const methodName,
  710. xmlrpc_response_handler responseHandler,
  711. void * const userData,
  712. xmlrpc_value * const argP) {
  713. xmlrpc_env env;
  714. xmlrpc_env_init(&env);
  715. XMLRPC_ASSERT_PTR_OK(serverP);
  716. XMLRPC_ASSERT_PTR_OK(methodName);
  717. XMLRPC_ASSERT_PTR_OK(responseHandler);
  718. XMLRPC_ASSERT_VALUE_OK(argP);
  719. if (!clientInitialized)
  720. xmlrpc_env_set_fault_formatted(
  721. &env, XMLRPC_INTERNAL_ERROR,
  722. "Xmlrpc-c client instance has not been initialized "
  723. "(need to call xmlrpc_client_init2()).");
  724. else
  725. sendRequest(&env, client.transportP, serverP,
  726. methodName, responseHandler, userData,
  727. argP);
  728. xmlrpc_env_clean(&env);
  729. }
  730. void
  731. xmlrpc_server_info_set_basic_auth(xmlrpc_env * const envP,
  732. xmlrpc_server_info * const serverP,
  733. const char * const username,
  734. const char * const password) {
  735. size_t username_len, password_len, raw_token_len;
  736. char *raw_token;
  737. xmlrpc_mem_block *token;
  738. char *token_data, *auth_type, *auth_header;
  739. size_t token_len, auth_type_len, auth_header_len;
  740. /* Error-handling preconditions. */
  741. raw_token = NULL;
  742. token = NULL;
  743. token_data = auth_type = auth_header = NULL;
  744. XMLRPC_ASSERT_ENV_OK(envP);
  745. XMLRPC_ASSERT_PTR_OK(serverP);
  746. XMLRPC_ASSERT_PTR_OK(username);
  747. XMLRPC_ASSERT_PTR_OK(password);
  748. /* Calculate some lengths. */
  749. username_len = strlen(username);
  750. password_len = strlen(password);
  751. raw_token_len = username_len + password_len + 1;
  752. /* Build a raw token of the form 'username:password'. */
  753. raw_token = (char*) malloc(raw_token_len + 1);
  754. XMLRPC_FAIL_IF_NULL(raw_token, envP, XMLRPC_INTERNAL_ERROR,
  755. "Couldn't allocate memory for auth token");
  756. strcpy(raw_token, username);
  757. raw_token[username_len] = ':';
  758. strcpy(&raw_token[username_len + 1], password);
  759. /* Encode our raw token using Base64. */
  760. token = xmlrpc_base64_encode_without_newlines(envP,
  761. (unsigned char*) raw_token,
  762. raw_token_len);
  763. XMLRPC_FAIL_IF_FAULT(envP);
  764. token_data = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, token);
  765. token_len = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, token);
  766. /* Build our actual header value. (I hate string processing in C.) */
  767. auth_type = "Basic ";
  768. auth_type_len = strlen(auth_type);
  769. auth_header_len = auth_type_len + token_len;
  770. auth_header = (char*) malloc(auth_header_len + 1);
  771. XMLRPC_FAIL_IF_NULL(auth_header, envP, XMLRPC_INTERNAL_ERROR,
  772. "Couldn't allocate memory for auth header");
  773. memcpy(auth_header, auth_type, auth_type_len);
  774. memcpy(&auth_header[auth_type_len], token_data, token_len);
  775. auth_header[auth_header_len] = '\0';
  776. /* Clean up any pre-existing authentication information, and install
  777. ** the new value. */
  778. if (serverP->_http_basic_auth)
  779. free(serverP->_http_basic_auth);
  780. serverP->_http_basic_auth = auth_header;
  781. cleanup:
  782. if (raw_token)
  783. free(raw_token);
  784. if (token)
  785. xmlrpc_mem_block_free(token);
  786. if (envP->fault_occurred) {
  787. if (auth_header)
  788. free(auth_header);
  789. }
  790. }