1 /* Copyright information is at end of file */
3 #include "xmlrpc_config.h"
17 #include "mallocvar.h"
19 #include "xmlrpc-c/base.h"
20 #include "xmlrpc-c/base_int.h"
21 #include "xmlrpc-c/string_int.h"
22 #include "xmlrpc-c/client.h"
23 #include "xmlrpc-c/client_int.h"
24 /* transport_config.h defines XMLRPC_DEFAULT_TRANSPORT,
25 MUST_BUILD_WININET_CLIENT, MUST_BUILD_CURL_CLIENT,
26 MUST_BUILD_LIBWWW_CLIENT
28 #include "transport_config.h"
30 #if MUST_BUILD_WININET_CLIENT
31 #include "xmlrpc_wininet_transport.h"
33 #if MUST_BUILD_CURL_CLIENT
34 #include "xmlrpc_curl_transport.h"
36 #if MUST_BUILD_LIBWWW_CLIENT
37 #include "xmlrpc_libwww_transport.h"
40 struct xmlrpc_client {
41 /*----------------------------------------------------------------------------
42 This represents a client object.
43 -----------------------------------------------------------------------------*/
44 struct xmlrpc_client_transport * transportP;
45 struct xmlrpc_client_transport_ops clientTransportOps;
50 typedef struct xmlrpc_call_info {
51 /* These fields are used when performing asynchronous calls.
52 ** The _asynch_data_holder contains server_url, method_name and
53 ** param_array, so it's the only thing we need to free. */
54 xmlrpc_value *_asynch_data_holder;
57 xmlrpc_value *param_array;
58 xmlrpc_response_handler callback;
61 /* The serialized XML data passed to this call. We keep this around
62 ** for use by our source_anchor field. */
63 xmlrpc_mem_block *serialized_xml;
68 /*=========================================================================
69 Global Constant Setup/Teardown
70 =========================================================================*/
73 callTransportSetup(xmlrpc_env * const envP,
74 xmlrpc_transport_setup setupFn) {
83 setupTransportGlobalConst(xmlrpc_env * const envP) {
85 #if MUST_BUILD_WININET_CLIENT
86 if (!envP->fault_occurred)
87 callTransportSetup(envP,
88 xmlrpc_wininet_transport_ops.setup_global_const);
90 #if MUST_BUILD_CURL_CLIENT
91 if (!envP->fault_occurred)
92 callTransportSetup(envP,
93 xmlrpc_curl_transport_ops.setup_global_const);
95 #if MUST_BUILD_LIBWWW_CLIENT
96 if (!envP->fault_occurred)
97 callTransportSetup(envP,
98 xmlrpc_libwww_transport_ops.setup_global_const);
105 callTransportTeardown(xmlrpc_transport_teardown teardownFn) {
114 teardownTransportGlobalConst(void) {
116 #if MUST_BUILD_WININET_CLIENT
117 callTransportTeardown(
118 xmlrpc_wininet_transport_ops.teardown_global_const);
120 #if MUST_BUILD_CURL_CLIENT
121 callTransportTeardown(
122 xmlrpc_curl_transport_ops.teardown_global_const);
124 #if MUST_BUILD_LIBWWW_CLIENT
125 callTransportTeardown(
126 xmlrpc_libwww_transport_ops.teardown_global_const);
132 static unsigned int constSetupCount = 0;
136 xmlrpc_client_setup_global_const(xmlrpc_env * const envP) {
137 /*----------------------------------------------------------------------------
138 Set up pseudo-constant global variables (they'd be constant, except that
139 the library loader doesn't set them. An explicit call from the loaded
142 This function is not thread-safe. The user is supposed to call it
143 (perhaps cascaded down from a multitude of higher level libraries)
144 as part of early program setup, when the program is only one thread.
145 -----------------------------------------------------------------------------*/
146 if (constSetupCount == 0)
147 setupTransportGlobalConst(envP);
155 xmlrpc_client_teardown_global_const(void) {
156 /*----------------------------------------------------------------------------
157 Complement to xmlrpc_client_setup_global_const().
159 This function is not thread-safe. The user is supposed to call it
160 (perhaps cascaded down from a multitude of higher level libraries)
161 as part of final program cleanup, when the program is only one thread.
162 -----------------------------------------------------------------------------*/
163 assert(constSetupCount > 0);
167 if (constSetupCount == 0)
168 teardownTransportGlobalConst();
173 /*=========================================================================
174 Client Create/Destroy
175 =========================================================================*/
178 getTransportOps(xmlrpc_env * const envP,
179 const char * const transportName,
180 struct xmlrpc_client_transport_ops * const opsP) {
184 #if MUST_BUILD_WININET_CLIENT
185 else if (strcmp(transportName, "wininet") == 0)
186 *opsP = xmlrpc_wininet_transport_ops;
188 #if MUST_BUILD_CURL_CLIENT
189 else if (strcmp(transportName, "curl") == 0)
190 *opsP = xmlrpc_curl_transport_ops;
192 #if MUST_BUILD_LIBWWW_CLIENT
193 else if (strcmp(transportName, "libwww") == 0)
194 *opsP = xmlrpc_libwww_transport_ops;
197 xmlrpc_env_set_fault_formatted(
198 envP, XMLRPC_INTERNAL_ERROR,
199 "Unrecognized XML transport name '%s'", transportName);
205 getTransportParmsFromClientParms(
206 xmlrpc_env * const envP,
207 const struct xmlrpc_clientparms * const clientparmsP,
208 unsigned int const parmSize,
209 const struct xmlrpc_xportparms ** const transportparmsPP,
210 size_t * const transportparmSizeP) {
212 if (parmSize < XMLRPC_CPSIZE(transportparmsP) ||
213 clientparmsP->transportparmsP == NULL) {
215 *transportparmsPP = NULL;
216 *transportparmSizeP = 0;
218 *transportparmsPP = clientparmsP->transportparmsP;
219 if (parmSize < XMLRPC_CPSIZE(transportparm_size))
220 xmlrpc_faultf(envP, "Your 'clientparms' argument contains the "
221 "transportparmsP member, "
222 "but no transportparms_size member");
224 *transportparmSizeP = clientparmsP->transportparm_size;
231 getTransportInfo(xmlrpc_env * const envP,
232 const struct xmlrpc_clientparms * const clientparmsP,
233 unsigned int const parmSize,
234 const char ** const transportNameP,
235 const struct xmlrpc_xportparms ** const transportparmsPP,
236 size_t * const transportparmSizeP) {
238 getTransportParmsFromClientParms(
239 envP, clientparmsP, parmSize,
240 transportparmsPP, transportparmSizeP);
242 if (!envP->fault_occurred) {
243 if (parmSize < XMLRPC_CPSIZE(transport) ||
244 clientparmsP->transport == NULL) {
246 /* He didn't specify a transport class. Use the default */
248 *transportNameP = xmlrpc_client_get_default_transport(envP);
249 if (*transportparmsPP)
251 "You specified transport parameters, but did not "
252 "specify a transport type. Parameters are specific to "
253 "a particular type.");
255 *transportNameP = clientparmsP->transport;
262 xmlrpc_client_create(xmlrpc_env * const envP,
264 const char * const appname,
265 const char * const appversion,
266 const struct xmlrpc_clientparms * const clientparmsP,
267 unsigned int const parmSize,
268 xmlrpc_client ** const clientPP) {
270 XMLRPC_ASSERT_PTR_OK(clientPP);
272 if (constSetupCount == 0) {
274 "You have not called "
275 "xmlrpc_client_setup_global_const().");
276 /* Impl note: We can't just call it now because it isn't
280 xmlrpc_client * clientP;
285 xmlrpc_faultf(envP, "Unable to allocate memory for "
286 "client descriptor.");
288 const char * transportName;
289 const struct xmlrpc_xportparms * transportparmsP;
290 size_t transportparmSize;
292 getTransportInfo(envP, clientparmsP, parmSize, &transportName,
293 &transportparmsP, &transportparmSize);
295 if (!envP->fault_occurred) {
296 getTransportOps(envP, transportName,
297 &clientP->clientTransportOps);
298 if (!envP->fault_occurred) {
299 /* The following call is not thread-safe */
300 clientP->clientTransportOps.create(
301 envP, flags, appname, appversion,
302 transportparmsP, transportparmSize,
303 &clientP->transportP);
304 if (!envP->fault_occurred)
308 if (envP->fault_occurred)
317 xmlrpc_client_destroy(xmlrpc_client * const clientP) {
319 XMLRPC_ASSERT_PTR_OK(clientP);
321 clientP->clientTransportOps.destroy(clientP->transportP);
328 /*=========================================================================
329 Call/Response Utilities
330 =========================================================================*/
333 makeCallXml(xmlrpc_env * const envP,
334 const char * const methodName,
335 xmlrpc_value * const paramArrayP,
336 xmlrpc_mem_block ** const callXmlPP) {
338 XMLRPC_ASSERT_VALUE_OK(paramArrayP);
339 XMLRPC_ASSERT_PTR_OK(callXmlPP);
341 if (methodName == NULL)
342 xmlrpc_env_set_fault_formatted(
343 envP, XMLRPC_INTERNAL_ERROR,
344 "method name argument is NULL pointer");
346 xmlrpc_mem_block * callXmlP;
348 callXmlP = XMLRPC_MEMBLOCK_NEW(char, envP, 0);
349 if (!envP->fault_occurred) {
350 xmlrpc_serialize_call(envP, callXmlP, methodName, paramArrayP);
352 *callXmlPP = callXmlP;
354 if (envP->fault_occurred)
355 XMLRPC_MEMBLOCK_FREE(char, callXmlP);
362 /*=========================================================================
364 =========================================================================*/
367 xmlrpc_server_info_new(xmlrpc_env * const envP,
368 const char * const serverUrl) {
370 xmlrpc_server_info * serverInfoP;
372 XMLRPC_ASSERT_ENV_OK(envP);
373 XMLRPC_ASSERT_PTR_OK(serverUrl);
375 /* Allocate our memory blocks. */
376 MALLOCVAR(serverInfoP);
377 if (serverInfoP == NULL)
378 xmlrpc_faultf(envP, "Couldn't allocate memory for xmlrpc_server_info");
380 memset(serverInfoP, 0, sizeof(xmlrpc_server_info));
382 serverInfoP->_server_url = strdup(serverUrl);
383 if (serverInfoP->_server_url == NULL)
384 xmlrpc_faultf(envP, "Couldn't allocate memory for server URL");
386 serverInfoP->_http_basic_auth = NULL;
387 if (envP->fault_occurred)
388 xmlrpc_strfree(serverInfoP->_server_url);
390 if (envP->fault_occurred)
399 xmlrpc_server_info_copy(xmlrpc_env * const envP,
400 xmlrpc_server_info * const aserverInfoP) {
402 xmlrpc_server_info * serverInfoP;
404 XMLRPC_ASSERT_ENV_OK(envP);
405 XMLRPC_ASSERT_PTR_OK(aserverInfoP);
407 MALLOCVAR(serverInfoP);
408 if (serverInfoP == NULL)
410 "Couldn't allocate memory for xmlrpc_server_info");
412 serverInfoP->_server_url = strdup(aserverInfoP->_server_url);
413 if (serverInfoP->_server_url == NULL)
414 xmlrpc_faultf(envP, "Couldn't allocate memory for server URL");
416 if (aserverInfoP->_http_basic_auth == NULL)
417 serverInfoP->_http_basic_auth = NULL;
419 serverInfoP->_http_basic_auth =
420 strdup(aserverInfoP->_http_basic_auth);
421 if (serverInfoP->_http_basic_auth == NULL)
422 xmlrpc_faultf(envP, "Couldn't allocate memory "
423 "for authentication info");
425 if (envP->fault_occurred)
426 xmlrpc_strfree(serverInfoP->_server_url);
428 if (envP->fault_occurred)
437 xmlrpc_server_info_free(xmlrpc_server_info * const serverInfoP) {
439 XMLRPC_ASSERT_PTR_OK(serverInfoP);
440 XMLRPC_ASSERT(serverInfoP->_server_url != XMLRPC_BAD_POINTER);
442 if (serverInfoP->_http_basic_auth)
443 free(serverInfoP->_http_basic_auth);
444 serverInfoP->_http_basic_auth = XMLRPC_BAD_POINTER;
445 free(serverInfoP->_server_url);
446 serverInfoP->_server_url = XMLRPC_BAD_POINTER;
452 /*=========================================================================
454 =========================================================================*/
457 xmlrpc_client_transport_call2(
458 xmlrpc_env * const envP,
459 xmlrpc_client * const clientP,
460 const xmlrpc_server_info * const serverP,
461 xmlrpc_mem_block * const callXmlP,
462 xmlrpc_mem_block ** const respXmlPP) {
464 XMLRPC_ASSERT_PTR_OK(clientP);
465 XMLRPC_ASSERT_PTR_OK(serverP);
466 XMLRPC_ASSERT_PTR_OK(callXmlP);
467 XMLRPC_ASSERT_PTR_OK(respXmlPP);
469 clientP->clientTransportOps.call(
470 envP, clientP->transportP, serverP, callXmlP,
477 xmlrpc_client_call2(xmlrpc_env * const envP,
478 struct xmlrpc_client * const clientP,
479 const xmlrpc_server_info * const serverInfoP,
480 const char * const methodName,
481 xmlrpc_value * const paramArrayP,
482 xmlrpc_value ** const resultPP) {
484 xmlrpc_mem_block * callXmlP;
486 XMLRPC_ASSERT_ENV_OK(envP);
487 XMLRPC_ASSERT_PTR_OK(clientP);
488 XMLRPC_ASSERT_PTR_OK(serverInfoP);
489 XMLRPC_ASSERT_PTR_OK(paramArrayP);
491 makeCallXml(envP, methodName, paramArrayP, &callXmlP);
493 if (!envP->fault_occurred) {
494 xmlrpc_mem_block * respXmlP;
496 xmlrpc_traceXml("XML-RPC CALL",
497 XMLRPC_MEMBLOCK_CONTENTS(char, callXmlP),
498 XMLRPC_MEMBLOCK_SIZE(char, callXmlP));
500 clientP->clientTransportOps.call(
501 envP, clientP->transportP, serverInfoP, callXmlP, &respXmlP);
502 if (!envP->fault_occurred) {
504 const char * faultString;
506 xmlrpc_traceXml("XML-RPC RESPONSE",
507 XMLRPC_MEMBLOCK_CONTENTS(char, respXmlP),
508 XMLRPC_MEMBLOCK_SIZE(char, respXmlP));
510 xmlrpc_parse_response2(
512 XMLRPC_MEMBLOCK_CONTENTS(char, respXmlP),
513 XMLRPC_MEMBLOCK_SIZE(char, respXmlP),
514 resultPP, &faultCode, &faultString);
516 if (!envP->fault_occurred) {
518 xmlrpc_env_set_fault_formatted(
520 "RPC failed at server. %s", faultString);
521 xmlrpc_strfree(faultString);
523 XMLRPC_ASSERT_VALUE_OK(*resultPP);
525 XMLRPC_MEMBLOCK_FREE(char, respXmlP);
527 XMLRPC_MEMBLOCK_FREE(char, callXmlP);
534 clientCall2f_va(xmlrpc_env * const envP,
535 xmlrpc_client * const clientP,
536 const char * const serverUrl,
537 const char * const methodName,
538 const char * const format,
539 xmlrpc_value ** const resultPP,
546 XMLRPC_ASSERT_ENV_OK(envP);
547 XMLRPC_ASSERT_PTR_OK(serverUrl);
548 XMLRPC_ASSERT_PTR_OK(methodName);
549 XMLRPC_ASSERT_PTR_OK(format);
550 XMLRPC_ASSERT_PTR_OK(resultPP);
552 /* Build our argument value. */
553 xmlrpc_env_init(&argenv);
554 xmlrpc_build_value_va(&argenv, format, args, &argP, &suffix);
555 if (argenv.fault_occurred)
556 xmlrpc_env_set_fault_formatted(
557 envP, argenv.fault_code, "Invalid RPC arguments. "
558 "The format argument must indicate a single array, and the "
559 "following arguments must correspond to that format argument. "
560 "The failure is: %s",
561 argenv.fault_string);
563 XMLRPC_ASSERT_VALUE_OK(argP);
566 xmlrpc_faultf(envP, "Junk after the argument specifier: '%s'. "
567 "There must be exactly one argument.",
570 xmlrpc_server_info * serverInfoP;
572 serverInfoP = xmlrpc_server_info_new(envP, serverUrl);
574 if (!envP->fault_occurred) {
575 /* Perform the actual XML-RPC call. */
576 xmlrpc_client_call2(envP, clientP,
577 serverInfoP, methodName, argP, resultPP);
578 if (!envP->fault_occurred)
579 XMLRPC_ASSERT_VALUE_OK(*resultPP);
580 xmlrpc_server_info_free(serverInfoP);
585 xmlrpc_env_clean(&argenv);
591 xmlrpc_client_call2f(xmlrpc_env * const envP,
592 xmlrpc_client * const clientP,
593 const char * const serverUrl,
594 const char * const methodName,
595 xmlrpc_value ** const resultPP,
596 const char * const format,
601 va_start(args, format);
602 clientCall2f_va(envP, clientP, serverUrl,
603 methodName, format, resultPP, args);
609 /*=========================================================================
611 =========================================================================*/
614 call_info_set_asynch_data(xmlrpc_env * const env,
615 xmlrpc_call_info * const info,
616 const char * const server_url,
617 const char * const method_name,
618 xmlrpc_value * const argP,
619 xmlrpc_response_handler responseHandler,
620 void * const user_data) {
622 xmlrpc_value *holder;
624 /* Error-handling preconditions. */
627 XMLRPC_ASSERT_ENV_OK(env);
628 XMLRPC_ASSERT_PTR_OK(info);
629 XMLRPC_ASSERT(info->_asynch_data_holder == NULL);
630 XMLRPC_ASSERT_PTR_OK(server_url);
631 XMLRPC_ASSERT_PTR_OK(method_name);
632 XMLRPC_ASSERT_VALUE_OK(argP);
634 /* Install our callback and user_data.
635 ** (We're not responsible for destroying the user_data.) */
636 info->callback = responseHandler;
637 info->user_data = user_data;
639 /* Build an XML-RPC data structure to hold our other data. This makes
640 ** copies of server_url and method_name, and increments the reference
641 ** to the argument *argP. */
642 holder = xmlrpc_build_value(env, "(ssV)",
643 server_url, method_name, argP);
644 XMLRPC_FAIL_IF_FAULT(env);
646 /* Parse the newly-allocated structure into our public member variables.
647 ** This doesn't make any new references, so we can dispose of the whole
648 ** thing by DECREF'ing the one master reference. Nifty, huh? */
649 xmlrpc_parse_value(env, holder, "(ssV)",
653 XMLRPC_FAIL_IF_FAULT(env);
655 /* Hand over ownership of the holder to the call_info struct. */
656 info->_asynch_data_holder = holder;
660 if (env->fault_occurred) {
662 xmlrpc_DECREF(holder);
669 call_info_free(xmlrpc_call_info * const callInfoP) {
671 /* Assume the worst.. That only parts of the call_info are valid. */
673 XMLRPC_ASSERT_PTR_OK(callInfoP);
675 /* If this has been allocated, we're responsible for destroying it. */
676 if (callInfoP->_asynch_data_holder)
677 xmlrpc_DECREF(callInfoP->_asynch_data_holder);
679 /* Now we can blow away the XML data. */
680 if (callInfoP->serialized_xml)
681 xmlrpc_mem_block_free(callInfoP->serialized_xml);
689 call_info_new(xmlrpc_env * const envP,
690 const char * const methodName,
691 xmlrpc_value * const paramArrayP,
692 xmlrpc_call_info ** const callInfoPP) {
693 /*----------------------------------------------------------------------------
694 Create a call_info object. A call_info object represents an XML-RPC
696 -----------------------------------------------------------------------------*/
697 struct xmlrpc_call_info * callInfoP;
699 XMLRPC_ASSERT_PTR_OK(paramArrayP);
700 XMLRPC_ASSERT_PTR_OK(callInfoPP);
702 MALLOCVAR(callInfoP);
703 if (callInfoP == NULL)
704 xmlrpc_env_set_fault_formatted(
705 envP, XMLRPC_INTERNAL_ERROR,
706 "Couldn't allocate memory for xmlrpc_call_info");
708 xmlrpc_mem_block * callXmlP;
710 /* Clear contents. */
711 memset(callInfoP, 0, sizeof(*callInfoP));
713 makeCallXml(envP, methodName, paramArrayP, &callXmlP);
715 if (!envP->fault_occurred) {
716 xmlrpc_traceXml("XML-RPC CALL",
717 XMLRPC_MEMBLOCK_CONTENTS(char, callXmlP),
718 XMLRPC_MEMBLOCK_SIZE(char, callXmlP));
720 callInfoP->serialized_xml = callXmlP;
722 *callInfoPP = callInfoP;
724 if (envP->fault_occurred)
733 xmlrpc_client_event_loop_finish(xmlrpc_client * const clientP) {
735 XMLRPC_ASSERT_PTR_OK(clientP);
737 clientP->clientTransportOps.finish_asynch(
738 clientP->transportP, timeout_no, 0);
744 xmlrpc_client_event_loop_finish_timeout(xmlrpc_client * const clientP,
745 xmlrpc_timeout const timeout) {
747 XMLRPC_ASSERT_PTR_OK(clientP);
749 clientP->clientTransportOps.finish_asynch(
750 clientP->transportP, timeout_yes, timeout);
756 asynchComplete(struct xmlrpc_call_info * const callInfoP,
757 xmlrpc_mem_block * const responseXmlP,
758 xmlrpc_env const transportEnv) {
759 /*----------------------------------------------------------------------------
760 Complete an asynchronous XML-RPC call request.
762 This includes calling the user's RPC completion routine.
764 'transportEnv' describes an error that the transport
765 encountered in processing the call. If the transport successfully
766 sent the call to the server and processed the response but the
767 server failed the call, 'transportEnv' indicates no error, and the
768 response in *responseXmlP might very well indicate that the server
770 -----------------------------------------------------------------------------*/
772 xmlrpc_value * resultP;
774 xmlrpc_env_init(&env);
776 resultP = NULL; /* Just to quiet compiler warning */
778 if (transportEnv.fault_occurred)
779 xmlrpc_env_set_fault_formatted(
780 &env, transportEnv.fault_code,
781 "Client transport failed to execute the RPC. %s",
782 transportEnv.fault_string);
784 if (!env.fault_occurred) {
786 const char * faultString;
788 xmlrpc_parse_response2(&env,
789 XMLRPC_MEMBLOCK_CONTENTS(char, responseXmlP),
790 XMLRPC_MEMBLOCK_SIZE(char, responseXmlP),
791 &resultP, &faultCode, &faultString);
793 if (!env.fault_occurred) {
795 xmlrpc_env_set_fault_formatted(
797 "RPC failed at server. %s", faultString);
798 xmlrpc_strfree(faultString);
802 /* Call the user's callback function with the result */
803 (*callInfoP->callback)(callInfoP->server_url,
804 callInfoP->method_name,
805 callInfoP->param_array,
806 callInfoP->user_data, &env, resultP);
808 if (!env.fault_occurred)
809 xmlrpc_DECREF(resultP);
811 call_info_free(callInfoP);
813 xmlrpc_env_clean(&env);
819 xmlrpc_client_start_rpc(xmlrpc_env * const envP,
820 struct xmlrpc_client * const clientP,
821 xmlrpc_server_info * const serverInfoP,
822 const char * const methodName,
823 xmlrpc_value * const argP,
824 xmlrpc_response_handler responseHandler,
825 void * const userData) {
827 xmlrpc_call_info * callInfoP;
829 XMLRPC_ASSERT_ENV_OK(envP);
830 XMLRPC_ASSERT_PTR_OK(clientP);
831 XMLRPC_ASSERT_PTR_OK(serverInfoP);
832 XMLRPC_ASSERT_PTR_OK(methodName);
833 XMLRPC_ASSERT_PTR_OK(responseHandler);
834 XMLRPC_ASSERT_VALUE_OK(argP);
836 call_info_new(envP, methodName, argP, &callInfoP);
837 if (!envP->fault_occurred) {
838 call_info_set_asynch_data(envP, callInfoP,
839 serverInfoP->_server_url, methodName,
840 argP, responseHandler, userData);
841 if (!envP->fault_occurred)
842 clientP->clientTransportOps.send_request(
843 envP, clientP->transportP, serverInfoP,
844 callInfoP->serialized_xml,
845 &asynchComplete, callInfoP);
847 if (envP->fault_occurred)
848 call_info_free(callInfoP);
850 /* asynchComplete() will free *callInfoP */
858 xmlrpc_client_start_rpcf(xmlrpc_env * const envP,
859 xmlrpc_client * const clientP,
860 const char * const serverUrl,
861 const char * const methodName,
862 xmlrpc_response_handler responseHandler,
863 void * const userData,
864 const char * const format,
868 xmlrpc_value * paramArrayP;
871 XMLRPC_ASSERT_PTR_OK(serverUrl);
872 XMLRPC_ASSERT_PTR_OK(format);
874 /* Build our argument array. */
875 va_start(args, format);
876 xmlrpc_build_value_va(envP, format, args, ¶mArrayP, &suffix);
878 if (!envP->fault_occurred) {
880 xmlrpc_faultf(envP, "Junk after the argument "
882 "There must be exactly one arument.",
885 xmlrpc_server_info * serverInfoP;
887 serverInfoP = xmlrpc_server_info_new(envP, serverUrl);
888 if (!envP->fault_occurred) {
889 xmlrpc_client_start_rpc(
891 serverInfoP, methodName, paramArrayP,
892 responseHandler, userData);
894 xmlrpc_server_info_free(serverInfoP);
896 xmlrpc_DECREF(paramArrayP);
902 /*=========================================================================
904 =========================================================================*/
907 xmlrpc_server_info_set_basic_auth(xmlrpc_env * const envP,
908 xmlrpc_server_info * const serverP,
909 const char * const username,
910 const char * const password) {
912 size_t username_len, password_len, raw_token_len;
914 xmlrpc_mem_block *token;
915 char *token_data, *auth_type, *auth_header;
916 size_t token_len, auth_type_len, auth_header_len;
918 /* Error-handling preconditions. */
921 token_data = auth_type = auth_header = NULL;
923 XMLRPC_ASSERT_ENV_OK(envP);
924 XMLRPC_ASSERT_PTR_OK(serverP);
925 XMLRPC_ASSERT_PTR_OK(username);
926 XMLRPC_ASSERT_PTR_OK(password);
928 /* Calculate some lengths. */
929 username_len = strlen(username);
930 password_len = strlen(password);
931 raw_token_len = username_len + password_len + 1;
933 /* Build a raw token of the form 'username:password'. */
934 raw_token = (char*) malloc(raw_token_len + 1);
935 XMLRPC_FAIL_IF_NULL(raw_token, envP, XMLRPC_INTERNAL_ERROR,
936 "Couldn't allocate memory for auth token");
937 strcpy(raw_token, username);
938 raw_token[username_len] = ':';
939 strcpy(&raw_token[username_len + 1], password);
941 /* Encode our raw token using Base64. */
942 token = xmlrpc_base64_encode_without_newlines(envP,
943 (unsigned char*) raw_token,
945 XMLRPC_FAIL_IF_FAULT(envP);
946 token_data = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, token);
947 token_len = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, token);
949 /* Build our actual header value. (I hate string processing in C.) */
950 auth_type = "Basic ";
951 auth_type_len = strlen(auth_type);
952 auth_header_len = auth_type_len + token_len;
953 auth_header = (char*) malloc(auth_header_len + 1);
954 XMLRPC_FAIL_IF_NULL(auth_header, envP, XMLRPC_INTERNAL_ERROR,
955 "Couldn't allocate memory for auth header");
956 memcpy(auth_header, auth_type, auth_type_len);
957 memcpy(&auth_header[auth_type_len], token_data, token_len);
958 auth_header[auth_header_len] = '\0';
960 /* Clean up any pre-existing authentication information, and install
962 if (serverP->_http_basic_auth)
963 free(serverP->_http_basic_auth);
964 serverP->_http_basic_auth = auth_header;
970 xmlrpc_mem_block_free(token);
971 if (envP->fault_occurred) {
980 xmlrpc_client_get_default_transport(xmlrpc_env * const env ATTR_UNUSED) {
982 return XMLRPC_DEFAULT_TRANSPORT;
987 /* Copyright (C) 2001 by First Peer, Inc. All rights reserved.
989 ** Redistribution and use in source and binary forms, with or without
990 ** modification, are permitted provided that the following conditions
992 ** 1. Redistributions of source code must retain the above copyright
993 ** notice, this list of conditions and the following disclaimer.
994 ** 2. Redistributions in binary form must reproduce the above copyright
995 ** notice, this list of conditions and the following disclaimer in the
996 ** documentation and/or other materials provided with the distribution.
997 ** 3. The name of the author may not be used to endorse or promote products
998 ** derived from this software without specific prior written permission.
1000 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1001 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1002 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1003 ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1004 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1005 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1006 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1007 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1008 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1009 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF