1 /* Copyright (C) 2001 by First Peer, Inc. All rights reserved.
3 ** Redistribution and use in source and binary forms, with or without
4 ** modification, are permitted provided that the following conditions
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.
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
26 #include "xmlrpc_config.h"
35 #include "xmlrpc_int.h"
36 #include "xmlrpc_xmlparser.h"
39 /*=========================================================================
41 **=========================================================================
42 ** All XML-RPC documents contain a single methodCall or methodResponse
45 ** methodCall methodName, params
46 ** methodResponse (params|fault)
50 ** value (i4|int|boolean|string|double|dateTime.iso8601|base64|
57 ** Contain CDATA: methodName, i4, int, boolean, string, double,
58 ** dateTime.iso8601, base64, name
60 ** We attempt to validate the structure of the XML document carefully.
61 ** We also try *very* hard to handle malicious data gracefully, and without
64 ** The CHECK_NAME and CHECK_CHILD_COUNT macros examine an XML element, and
65 ** invoke XMLRPC_FAIL if something looks wrong.
68 #define CHECK_NAME(env,elem,name) \
70 if (strcmp((name), xml_element_name(elem)) != 0) \
71 XMLRPC_FAIL2(env, XMLRPC_PARSE_ERROR, \
72 "Expected element of type <%s>, found <%s>", \
73 (name), xml_element_name(elem)); \
76 #define CHECK_CHILD_COUNT(env,elem,count) \
78 if (xml_element_children_size(elem) != (count)) \
79 XMLRPC_FAIL3(env, XMLRPC_PARSE_ERROR, \
80 "Expected <%s> to have %d children, found %d", \
81 xml_element_name(elem), (count), \
82 xml_element_children_size(elem)); \
86 get_child_by_name (xmlrpc_env
*env
, xml_element
*parent
, char *name
)
88 size_t child_count
, i
;
89 xml_element
**children
;
91 children
= xml_element_children(parent
);
92 child_count
= xml_element_children_size(parent
);
93 for (i
= 0; i
< child_count
; i
++) {
94 if (0 == strcmp(xml_element_name(children
[i
]), name
))
98 xmlrpc_env_set_fault_formatted(env
, XMLRPC_PARSE_ERROR
,
99 "Expected <%s> to have child <%s>",
100 xml_element_name(parent
), name
);
105 /*=========================================================================
106 ** Number-Parsing Functions
107 **=========================================================================
108 ** These functions mirror atoi, atof, etc., but provide better
109 ** error-handling. These routines may reset errno to zero.
113 xmlrpc_atoi(xmlrpc_env
*env
, char *str
, size_t stringLength
,
114 xmlrpc_int32 min
, xmlrpc_int32 max
)
119 XMLRPC_ASSERT_ENV_OK(env
);
120 XMLRPC_ASSERT_PTR_OK(str
);
122 /* Suppress compiler warnings. */
125 /* Check for leading white space. */
126 if (isspace((int)(str
[0])))
127 XMLRPC_FAIL1(env
, XMLRPC_PARSE_ERROR
,
128 "\"%s\" must not contain whitespace", str
);
130 /* Convert the value. */
131 end
= str
+ stringLength
;
133 i
= strtol(str
, &end
, 10);
135 /* Look for ERANGE. */
137 /* XXX - Do all operating systems have thread-safe strerror? */
138 XMLRPC_FAIL3(env
, XMLRPC_PARSE_ERROR
,
139 "error parsing \"%s\": %s (%d)",
140 str
, strerror(errno
), errno
);
142 /* Look for out-of-range errors which didn't produce ERANGE. */
143 if (i
< min
|| i
> max
)
144 XMLRPC_FAIL3(env
, XMLRPC_PARSE_ERROR
,
145 "\"%s\" must be in range %d to %d", str
, min
, max
);
147 /* Check for unused characters. */
148 if (end
!= str
+ stringLength
)
149 XMLRPC_FAIL1(env
, XMLRPC_PARSE_ERROR
,
150 "\"%s\" contained trailing data", str
);
154 if (env
->fault_occurred
)
156 return (xmlrpc_int32
) i
;
162 xmlrpc_atod(xmlrpc_env
*env
, char *str
, size_t stringLength
)
167 XMLRPC_ASSERT_ENV_OK(env
);
168 XMLRPC_ASSERT_PTR_OK(str
);
170 /* Suppress compiler warnings. */
173 /* Check for leading white space. */
174 if (isspace((int)(str
[0])))
175 XMLRPC_FAIL1(env
, XMLRPC_PARSE_ERROR
,
176 "\"%s\" must not contain whitespace", str
);
178 /* Convert the value. */
179 end
= str
+ stringLength
;
181 d
= strtod(str
, &end
);
183 /* Look for ERANGE. */
185 /* XXX - Do all operating systems have thread-safe strerror? */
186 XMLRPC_FAIL3(env
, XMLRPC_PARSE_ERROR
,
187 "error parsing \"%s\": %s (%d)",
188 str
, strerror(errno
), errno
);
190 /* Check for unused characters. */
191 if (end
!= str
+ stringLength
)
192 XMLRPC_FAIL1(env
, XMLRPC_PARSE_ERROR
,
193 "\"%s\" contained trailing data", str
);
197 if (env
->fault_occurred
)
203 /*=========================================================================
205 **=========================================================================
206 ** Make an XML-RPC string.
208 ** SECURITY: We validate our UTF-8 first. This incurs a performance
209 ** penalty, but ensures that we will never pass maliciously malformed
210 ** UTF-8 data back up to the user layer, where it could wreak untold
211 ** damange. Don't comment out this check unless you know *exactly* what
212 ** you're doing. (Win32 developers who remove this check are *begging*
213 ** to wind up on BugTraq, because many of the Win32 filesystem routines
214 ** rely on an insecure UTF-8 decoder.)
216 ** XXX - This validation is redundant if the user chooses to convert
217 ** UTF-8 data into a wchar_t string.
220 static xmlrpc_value
*
221 make_string(xmlrpc_env
*env
, char *cdata
, size_t cdata_size
)
223 #ifdef HAVE_UNICODE_WCHAR
224 xmlrpc_validate_utf8(env
, cdata
, cdata_size
);
227 if (env
->fault_occurred
)
229 return xmlrpc_build_value(env
, "s#", cdata
, cdata_size
);
234 /*=========================================================================
236 **=========================================================================
237 ** Convert an XML element representing a value into an xmlrpc_value.
240 static xmlrpc_value
*
241 convert_array (xmlrpc_env
*env
, unsigned *depth
, xml_element
*elem
);
242 static xmlrpc_value
*
243 convert_struct(xmlrpc_env
*env
, unsigned *depth
, xml_element
*elem
);
247 static xmlrpc_value
*
248 convert_value(xmlrpc_env
*env
, unsigned *depth
, xml_element
*elem
)
252 char *cdata
, *child_name
;
253 size_t cdata_size
, ascii_len
;
254 xmlrpc_mem_block
*decoded
;
255 unsigned char *ascii_data
;
256 xmlrpc_value
*retval
;
260 XMLRPC_ASSERT_ENV_OK(env
);
261 XMLRPC_ASSERT(elem
!= NULL
);
263 /* Error-handling precoditions.
264 ** If we haven't changed any of these from their default state, we're
265 ** allowed to tail-call xmlrpc_build_value. */
269 /* Make sure we haven't recursed too deeply. */
270 if (*depth
> xmlrpc_limit_get(XMLRPC_NESTING_LIMIT_ID
))
271 XMLRPC_FAIL(env
, XMLRPC_PARSE_ERROR
,
272 "Nested data structure too deep.");
274 /* Validate our structure, and see whether we have a child element. */
275 CHECK_NAME(env
, elem
, "value");
276 child_count
= xml_element_children_size(elem
);
278 if (child_count
== 0) {
279 /* We have no type element, so treat the value as a string. */
280 cdata
= xml_element_cdata(elem
);
281 cdata_size
= xml_element_cdata_size(elem
);
282 return make_string(env
, cdata
, cdata_size
);
284 /* We should have a type tag inside our value tag. */
285 CHECK_CHILD_COUNT(env
, elem
, 1);
286 child
= xml_element_children(elem
)[0];
288 /* Parse our value-containing element. */
289 child_name
= xml_element_name(child
);
290 if (strcmp(child_name
, "struct") == 0) {
291 return convert_struct(env
, depth
, child
);
292 } else if (strcmp(child_name
, "array") == 0) {
293 CHECK_CHILD_COUNT(env
, child
, 1);
294 return convert_array(env
, depth
, child
);
296 CHECK_CHILD_COUNT(env
, child
, 0);
297 cdata
= xml_element_cdata(child
);
298 cdata_size
= xml_element_cdata_size(child
);
299 if (strcmp(child_name
, "i4") == 0 ||
300 strcmp(child_name
, "int") == 0)
302 i
= xmlrpc_atoi(env
, cdata
, strlen(cdata
),
303 XMLRPC_INT32_MIN
, XMLRPC_INT32_MAX
);
304 XMLRPC_FAIL_IF_FAULT(env
);
305 return xmlrpc_build_value(env
, "i", i
);
306 } else if (strcmp(child_name
, "string") == 0) {
307 return make_string(env
, cdata
, cdata_size
);
308 } else if (strcmp(child_name
, "boolean") == 0) {
309 i
= xmlrpc_atoi(env
, cdata
, strlen(cdata
), 0, 1);
310 XMLRPC_FAIL_IF_FAULT(env
);
311 return xmlrpc_build_value(env
, "b", (xmlrpc_bool
) i
);
312 } else if (strcmp(child_name
, "double") == 0) {
313 d
= xmlrpc_atod(env
, cdata
, strlen(cdata
));
314 XMLRPC_FAIL_IF_FAULT(env
);
315 return xmlrpc_build_value(env
, "d", d
);
316 } else if (strcmp(child_name
, "dateTime.iso8601") == 0) {
317 return xmlrpc_build_value(env
, "8", cdata
);
318 } else if (strcmp(child_name
, "base64") == 0) {
319 /* No more tail calls once we do this! */
320 decoded
= xmlrpc_base64_decode(env
, cdata
, cdata_size
);
321 XMLRPC_FAIL_IF_FAULT(env
);
322 ascii_data
= XMLRPC_TYPED_MEM_BLOCK_CONTENTS(unsigned char,
324 ascii_len
= XMLRPC_TYPED_MEM_BLOCK_SIZE(unsigned char,
326 retval
= xmlrpc_build_value(env
, "6", ascii_data
, ascii_len
);
327 XMLRPC_FAIL_IF_FAULT(env
);
329 XMLRPC_FAIL1(env
, XMLRPC_PARSE_ERROR
,
330 "Unknown value type <%s>", child_name
);
337 xmlrpc_mem_block_free(decoded
);
338 if (env
->fault_occurred
) {
340 xmlrpc_DECREF(retval
);
348 /*=========================================================================
350 **=========================================================================
351 ** Convert an XML element representing an array into an xmlrpc_value.
354 static xmlrpc_value
*
355 convert_array(xmlrpc_env
*env
, unsigned *depth
, xml_element
*elem
)
357 xml_element
*data
, **values
, *value
;
358 xmlrpc_value
*array
, *item
;
361 XMLRPC_ASSERT_ENV_OK(env
);
362 XMLRPC_ASSERT(elem
!= NULL
);
364 /* Set up our error-handling preconditions. */
368 /* Allocate an array to hold our values. */
369 array
= xmlrpc_build_value(env
, "()");
370 XMLRPC_FAIL_IF_FAULT(env
);
372 /* We don't need to check our element name--our callers do that. */
373 CHECK_CHILD_COUNT(env
, elem
, 1);
374 data
= xml_element_children(elem
)[0];
375 CHECK_NAME(env
, data
, "data");
377 /* Iterate over our children. */
378 values
= xml_element_children(data
);
379 size
= xml_element_children_size(data
);
380 for (i
= 0; i
< size
; i
++) {
382 item
= convert_value(env
, depth
, value
);
383 XMLRPC_FAIL_IF_FAULT(env
);
385 xmlrpc_array_append_item(env
, array
, item
);
388 XMLRPC_FAIL_IF_FAULT(env
);
395 if (env
->fault_occurred
) {
397 xmlrpc_DECREF(array
);
405 /*=========================================================================
407 **=========================================================================
408 ** Convert an XML element representing a struct into an xmlrpc_value.
411 static xmlrpc_value
*
412 convert_struct(xmlrpc_env
*env
, unsigned *depth
, xml_element
*elem
)
414 xmlrpc_value
*strct
, *key
, *value
;
415 xml_element
**members
, *member
, *name_elem
, *value_elem
;
420 XMLRPC_ASSERT_ENV_OK(env
);
421 XMLRPC_ASSERT(elem
!= NULL
);
423 /* Set up our error-handling preconditions. */
427 /* Allocate an array to hold our members. */
428 strct
= xmlrpc_struct_new(env
);
429 XMLRPC_FAIL_IF_FAULT(env
);
431 /* Iterate over our children, extracting key/value pairs. */
432 /* We don't need to check our element name--our callers do that. */
433 members
= xml_element_children(elem
);
434 size
= xml_element_children_size(elem
);
435 for (i
= 0; i
< size
; i
++) {
437 CHECK_NAME(env
, member
, "member");
438 CHECK_CHILD_COUNT(env
, member
, 2);
441 name_elem
= get_child_by_name(env
, member
, "name");
442 XMLRPC_FAIL_IF_FAULT(env
);
443 CHECK_CHILD_COUNT(env
, name_elem
, 0);
444 cdata
= xml_element_cdata(name_elem
);
445 cdata_size
= xml_element_cdata_size(name_elem
);
446 key
= make_string(env
, cdata
, cdata_size
);
447 XMLRPC_FAIL_IF_FAULT(env
);
450 value_elem
= get_child_by_name(env
, member
, "value");
451 XMLRPC_FAIL_IF_FAULT(env
);
452 value
= convert_value(env
, depth
, value_elem
);
453 XMLRPC_FAIL_IF_FAULT(env
);
455 /* Add the key/value pair to our struct. */
456 xmlrpc_struct_set_value_v(env
, strct
, key
, value
);
457 XMLRPC_FAIL_IF_FAULT(env
);
459 /* Release our references & memory, and restore our invariants. */
462 xmlrpc_DECREF(value
);
471 xmlrpc_DECREF(value
);
472 if (env
->fault_occurred
) {
474 xmlrpc_DECREF(strct
);
482 /*=========================================================================
484 **=========================================================================
485 ** Convert an XML element representing a list of params into an
486 ** xmlrpc_value (of type array).
489 static xmlrpc_value
*
490 convert_params(xmlrpc_env
*env
, unsigned *depth
, xml_element
*elem
)
492 xmlrpc_value
*array
, *item
;
494 xml_element
**params
, *param
, *value
;
496 XMLRPC_ASSERT_ENV_OK(env
);
497 XMLRPC_ASSERT(elem
!= NULL
);
499 /* Set up our error-handling preconditions. */
502 /* Allocate an array to hold our parameters. */
503 array
= xmlrpc_build_value(env
, "()");
504 XMLRPC_FAIL_IF_FAULT(env
);
506 /* We're responsible for checking our own element name. */
507 CHECK_NAME(env
, elem
, "params");
509 /* Iterate over our children. */
510 size
= xml_element_children_size(elem
);
511 params
= xml_element_children(elem
);
512 for (i
= 0; i
< size
; i
++) {
514 CHECK_NAME(env
, param
, "param");
515 CHECK_CHILD_COUNT(env
, param
, 1);
517 value
= xml_element_children(param
)[0];
518 item
= convert_value(env
, depth
, value
);
519 XMLRPC_FAIL_IF_FAULT(env
);
521 xmlrpc_array_append_item(env
, array
, item
);
524 XMLRPC_FAIL_IF_FAULT(env
);
528 if (env
->fault_occurred
) {
530 xmlrpc_DECREF(array
);
541 parseCallXml(xmlrpc_env
* const envP
,
542 const char * const xmlData
,
544 xml_element
** const callElemP
) {
548 xmlrpc_env_init(&env
);
549 *callElemP
= xml_parse(&env
, xmlData
, (int)xmlLen
);
550 if (env
.fault_occurred
)
551 xmlrpc_env_set_fault_formatted(
552 envP
, env
.fault_code
, "Call is not valid XML. %s",
554 xmlrpc_env_clean(&env
);
559 /*=========================================================================
561 **=========================================================================
562 ** Given some XML text, attempt to parse it as an XML-RPC call. Return
563 ** a newly allocated xmlrpc_call structure (or NULL, if an error occurs).
564 ** The two output variables will contain either valid values (which
565 ** must free() and xmlrpc_DECREF(), respectively) or NULLs (if an error
570 xmlrpc_parse_call(xmlrpc_env
* const envP
,
571 const char * const xml_data
,
572 size_t const xml_len
,
573 const char ** const out_method_nameP
,
574 xmlrpc_value
** const out_param_arrayPP
) {
576 xml_element
*call_elem
, *name_elem
, *params_elem
;
579 size_t call_child_count
;
580 char * outMethodName
;
581 xmlrpc_value
* outParamArrayP
;
583 XMLRPC_ASSERT_ENV_OK(envP
);
584 XMLRPC_ASSERT(xml_data
!= NULL
);
585 XMLRPC_ASSERT(out_method_nameP
!= NULL
&& out_param_arrayPP
!= NULL
);
587 /* Set up our error-handling preconditions. */
588 outMethodName
= NULL
;
589 outParamArrayP
= NULL
;
592 /* SECURITY: Last-ditch attempt to make sure our content length is legal.
593 ** XXX - This check occurs too late to prevent an attacker from creating
594 ** an enormous memory block in RAM, so you should try to enforce it
595 ** *before* reading any data off the network. */
596 if (xml_len
> xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID
))
597 XMLRPC_FAIL(envP
, XMLRPC_LIMIT_EXCEEDED_ERROR
,
598 "XML-RPC request too large");
600 parseCallXml(envP
, xml_data
, xml_len
, &call_elem
);
601 XMLRPC_FAIL_IF_FAULT(envP
);
603 /* Pick apart and verify our structure. */
604 CHECK_NAME(envP
, call_elem
, "methodCall");
605 call_child_count
= xml_element_children_size(call_elem
);
606 if (call_child_count
!= 2 && call_child_count
!= 1)
607 XMLRPC_FAIL1(envP
, XMLRPC_PARSE_ERROR
,
608 "Expected <methodCall> to have 1 or 2 children, found %d",
611 /* Extract the method name.
612 ** SECURITY: We make sure the method name is valid UTF-8. */
613 name_elem
= get_child_by_name(envP
, call_elem
, "methodName");
614 XMLRPC_FAIL_IF_FAULT(envP
);
615 CHECK_CHILD_COUNT(envP
, name_elem
, 0);
616 cdata
= xml_element_cdata(name_elem
);
617 #ifdef HAVE_UNICODE_WCHAR
618 xmlrpc_validate_utf8(envP
, cdata
, strlen(cdata
));
619 XMLRPC_FAIL_IF_FAULT(envP
);
620 #endif /* HAVE_UNICODE_WCHAR */
621 outMethodName
= malloc(strlen(cdata
) + 1);
622 XMLRPC_FAIL_IF_NULL(outMethodName
, envP
, XMLRPC_INTERNAL_ERROR
,
623 "Could not allocate memory for method name");
624 strcpy(outMethodName
, cdata
);
626 /* Convert our parameters. */
627 if (call_child_count
== 1) {
628 /* Workaround for Ruby XML-RPC and old versions of xmlrpc-epi. */
629 outParamArrayP
= xmlrpc_build_value(envP
, "()");
630 XMLRPC_FAIL_IF_FAULT(envP
);
632 params_elem
= get_child_by_name(envP
, call_elem
, "params");
633 XMLRPC_FAIL_IF_FAULT(envP
);
635 outParamArrayP
= convert_params(envP
, &depth
, params_elem
);
636 XMLRPC_ASSERT(depth
== 0);
637 XMLRPC_FAIL_IF_FAULT(envP
);
642 xml_element_free(call_elem
);
643 if (envP
->fault_occurred
) {
647 xmlrpc_DECREF(outParamArrayP
);
648 outMethodName
= NULL
;
649 outParamArrayP
= NULL
;
651 *out_method_nameP
= outMethodName
;
652 *out_param_arrayPP
= outParamArrayP
;
657 /*=========================================================================
658 ** xmlrpc_parse_response
659 **=========================================================================
660 ** Given some XML text, attempt to parse it as an XML-RPC response.
661 ** If the response is a regular, valid response, return a new reference
662 ** to the appropriate value. If the response is a fault, or an error
663 ** occurs during processing, return NULL and set up env appropriately.
667 xmlrpc_parse_response(xmlrpc_env
*env
,
668 const char *xml_data
,
671 xml_element
*response
, *child
, *value
;
673 xmlrpc_value
*params
, *retval
, *fault
;
674 int retval_incremented
;
676 xmlrpc_value
*fault_code_value
, *fault_str_value
;
677 xmlrpc_int32 fault_code
;
680 XMLRPC_ASSERT_ENV_OK(env
);
681 XMLRPC_ASSERT(xml_data
!= NULL
);
683 /* Set up our error-handling preconditions. */
685 params
= fault
= NULL
;
686 retval_incremented
= 0;
688 /* SECURITY: Last-ditch attempt to make sure our content length is legal.
689 ** XXX - This check occurs too late to prevent an attacker from creating
690 ** an enormous memory block in RAM, so you should try to enforce it
691 ** *before* reading any data off the network. */
692 if (xml_len
> xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID
))
693 XMLRPC_FAIL(env
, XMLRPC_LIMIT_EXCEEDED_ERROR
,
694 "XML-RPC response too large");
696 /* SECURITY: Set up our recursion depth counter. */
699 /* Parse our XML data. */
700 response
= xml_parse(env
, xml_data
, (int)xml_len
);
701 XMLRPC_FAIL_IF_FAULT(env
);
703 /* Pick apart and verify our structure. */
704 CHECK_NAME(env
, response
, "methodResponse");
705 CHECK_CHILD_COUNT(env
, response
, 1);
706 child
= xml_element_children(response
)[0];
708 /* Parse the response itself. */
709 if (strcmp("params", xml_element_name(child
)) == 0) {
711 /* Convert our parameter list. */
712 params
= convert_params(env
, &depth
, child
);
713 XMLRPC_FAIL_IF_FAULT(env
);
715 /* Extract the return value, and jiggle our reference counts. */
716 xmlrpc_parse_value(env
, params
, "(V)", &retval
);
717 XMLRPC_FAIL_IF_FAULT(env
);
718 xmlrpc_INCREF(retval
);
719 retval_incremented
= 1;
721 } else if (strcmp("fault", xml_element_name(child
)) == 0) {
723 /* Convert our fault structure. */
724 CHECK_CHILD_COUNT(env
, child
, 1);
725 value
= xml_element_children(child
)[0];
726 fault
= convert_value(env
, &depth
, value
);
727 XMLRPC_FAIL_IF_FAULT(env
);
728 XMLRPC_TYPE_CHECK(env
, fault
, XMLRPC_TYPE_STRUCT
);
730 /* Get our fault code. */
731 fault_code_value
= xmlrpc_struct_get_value(env
, fault
, "faultCode");
732 XMLRPC_FAIL_IF_FAULT(env
);
733 xmlrpc_parse_value(env
, fault_code_value
, "i", &fault_code
);
734 XMLRPC_FAIL_IF_FAULT(env
);
736 /* Get our fault string. */
737 fault_str_value
= xmlrpc_struct_get_value(env
, fault
, "faultString");
738 XMLRPC_FAIL_IF_FAULT(env
);
739 xmlrpc_parse_value(env
, fault_str_value
, "s", &fault_str
);
740 XMLRPC_FAIL_IF_FAULT(env
);
742 /* Return our fault. */
743 XMLRPC_FAIL(env
, fault_code
, fault_str
);
746 XMLRPC_FAIL(env
, XMLRPC_PARSE_ERROR
,
747 "Expected <params> or <fault> in <methodResponse>");
750 /* Sanity-check our depth-counting code. */
751 XMLRPC_ASSERT(depth
== 0);
755 xml_element_free(response
);
757 xmlrpc_DECREF(params
);
759 xmlrpc_DECREF(fault
);
761 if (env
->fault_occurred
) {
762 if (retval_incremented
)
763 xmlrpc_DECREF(retval
);