static void parseMethodResponseElt(xmlrpc_env * const envP, const xml_element * const methodResponseEltP, xmlrpc_value ** const resultPP, int * const faultCodeP, const char ** const faultStringP) { XMLRPC_ASSERT(xmlrpc_streq(xml_element_name(methodResponseEltP), "methodResponse")); if (xml_element_children_size(methodResponseEltP) == 1) { xml_element * const child = xml_element_children(methodResponseEltP)[0]; if (xmlrpc_streq(xml_element_name(child), "params")) { /* It's a successful response */ parseParamsElement(envP, child, resultPP); *faultStringP = NULL; } else if (xmlrpc_streq(xml_element_name(child), "fault")) { /* It's a failure response */ parseFaultElement(envP, child, faultCodeP, faultStringP); } else setParseFault(envP, "<methodResponse> must contain <params> or <fault>, " "but contains <%s>.", xml_element_name(child)); } else setParseFault(envP, "<methodResponse> has %u children, should have 1.", xml_element_children_size(methodResponseEltP)); }
static xmlrpc_value * convert_params(xmlrpc_env * const envP, const xml_element * const elemP) { /*---------------------------------------------------------------------------- Convert an XML element representing a list of parameters (i.e. a <params> element) to an xmlrpc_value of type array. Note that an array is normally represented in XML by a <value> element. We use type xmlrpc_value to represent the parameter list just for convenience. -----------------------------------------------------------------------------*/ xmlrpc_value *array, *item; int size, i; xml_element **params, *param, *value; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT(elemP != NULL); /* Set up our error-handling preconditions. */ array = item = NULL; /* Allocate an array to hold our parameters. */ array = xmlrpc_build_value(envP, "()"); XMLRPC_FAIL_IF_FAULT(envP); /* We're responsible for checking our own element name. */ CHECK_NAME(envP, elemP, "params"); /* Iterate over our children. */ size = xml_element_children_size(elemP); params = xml_element_children(elemP); for (i = 0; i < size; ++i) { unsigned int const maxNest = xmlrpc_limit_get(XMLRPC_NESTING_LIMIT_ID); param = params[i]; CHECK_NAME(envP, param, "param"); CHECK_CHILD_COUNT(envP, param, 1); value = xml_element_children(param)[0]; CHECK_NAME(envP, value, "value"); xmlrpc_parseValue(envP, maxNest, value, &item); XMLRPC_FAIL_IF_FAULT(envP); xmlrpc_array_append_item(envP, array, item); xmlrpc_DECREF(item); item = NULL; XMLRPC_FAIL_IF_FAULT(envP); } cleanup: if (envP->fault_occurred) { if (array) xmlrpc_DECREF(array); if (item) xmlrpc_DECREF(item); return NULL; } return array; }
static void parseArray(xmlrpc_env * const envP, unsigned int const maxRecursion, xml_element * const arrayElemP, xmlrpc_value ** const arrayPP) { xmlrpc_value * arrayP; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT(arrayElemP != NULL); arrayP = xmlrpc_array_new(envP); if (!envP->fault_occurred) { unsigned int const childCount = xml_element_children_size(arrayElemP); if (childCount != 1) setParseFault(envP, "<array> element has %u children. Only one <data> " "makes sense.", childCount); else { xml_element * const dataElemP = xml_element_children(arrayElemP)[0]; const char * const elemName = xml_element_name(dataElemP); if (!xmlrpc_streq(elemName, "data")) setParseFault(envP, "<array> element has <%s> child. Only <data> " "makes sense.", elemName); else { xml_element ** const values = xml_element_children(dataElemP); unsigned int const size = xml_element_children_size(dataElemP); unsigned int i; for (i = 0; i < size && !envP->fault_occurred; ++i) parseArrayDataChild(envP, values[i], maxRecursion, arrayP); } } if (envP->fault_occurred) xmlrpc_DECREF(arrayP); else *arrayPP = arrayP; } }
static void test_expat (void) { xmlrpc_env env; xml_element *elem, *array, *data, *value1, *i4; char *cdata; size_t size; xmlrpc_env_init(&env); /* Parse a moderately complex XML document. */ xml_parse(&env, expat_data, strlen(expat_data), &elem); TEST_NO_FAULT(&env); TEST(elem != NULL); /* Verify our results. */ TEST(streq(xml_element_name(elem), "value")); TEST(xml_element_children_size(elem) == 1); array = xml_element_children(elem)[0]; TEST(streq(xml_element_name(array), "array")); TEST(xml_element_children_size(array) == 1); data = xml_element_children(array)[0]; TEST(streq(xml_element_name(data), "data")); TEST(xml_element_children_size(data) > 1); value1 = xml_element_children(data)[0]; TEST(streq(xml_element_name(value1), "value")); TEST(xml_element_children_size(value1) == 1); i4 = xml_element_children(value1)[0]; TEST(streq(xml_element_name(i4), "i4")); TEST(xml_element_children_size(i4) == 0); cdata = xml_element_cdata(i4); size = xml_element_cdata_size(i4); TEST(size == strlen("2147483647")); TEST(memcmp(cdata, "2147483647", strlen("2147483647")) == 0); /* Test cleanup code (w/memprof). */ xml_element_free(elem); /* Test broken XML */ xml_parse(&env, expat_error_data, strlen(expat_error_data), &elem); TEST(env.fault_occurred); xmlrpc_env_clean(&env); }
static void describeXmlElement(const xml_element * const elemP, const char * const prefix) { unsigned int i; printf("%sXML element type: '%s'\n", prefix, xml_element_name(elemP)); printf("%sNumber of child elements: %u\n", prefix, xml_element_children_size(elemP)); for (i = 0; i < xml_element_children_size(elemP); ++i) { char * const newPrefix = malloc(strlen(prefix) + 2); sprintf(newPrefix, "%s ", prefix); describeXmlElement(xml_element_children(elemP)[i], newPrefix); free(newPrefix); } }
static void parseCallChildren(xmlrpc_env * const envP, xml_element * const callElemP, const char ** const methodNameP, xmlrpc_value ** const paramArrayPP ) { /*---------------------------------------------------------------------------- Parse the children of a <methodCall> XML element *callElemP. They should be <methodName> and <params>. -----------------------------------------------------------------------------*/ size_t const callChildCount = xml_element_children_size(callElemP); xml_element * nameElemP; XMLRPC_ASSERT(xmlrpc_streq(xml_element_name(callElemP), "methodCall")); nameElemP = getChildByName(envP, callElemP, "methodName"); if (!envP->fault_occurred) { parseMethodNameElement(envP, nameElemP, methodNameP); if (!envP->fault_occurred) { /* Convert our parameters. */ if (callChildCount > 1) { xml_element * paramsElemP; paramsElemP = getChildByName(envP, callElemP, "params"); if (!envP->fault_occurred) *paramArrayPP = convertParams(envP, paramsElemP); } else { /* Workaround for Ruby XML-RPC and old versions of xmlrpc-epi. Future improvement: Instead of looking at child count, we should just check for existence of <params>. */ *paramArrayPP = xmlrpc_array_new(envP); } if (!envP->fault_occurred) { if (callChildCount > 2) setParseFault(envP, "<methodCall> has extraneous " "children, other than <methodName> and " "<params>. Total child count = %u", callChildCount); if (envP->fault_occurred) xmlrpc_DECREF(*paramArrayPP); } if (envP->fault_occurred) xmlrpc_strfree(*methodNameP); } } }
static void parseFaultElement(xmlrpc_env * const envP, const xml_element * const faultElement, int * const faultCodeP, const char ** const faultStringP) { unsigned int const maxRecursion = (unsigned int) xmlrpc_limit_get(XMLRPC_NESTING_LIMIT_ID); XMLRPC_ASSERT(xmlrpc_streq(xml_element_name(faultElement), "fault")); if (xml_element_children_size(faultElement) != 1) setParseFault(envP, "<fault> element should have 1 child, " "but it has %u.", xml_element_children_size(faultElement)); else { xml_element * const faultValueP = xml_element_children(faultElement)[0]; const char * const elemName = xml_element_name(faultValueP); if (!xmlrpc_streq(elemName, "value")) setParseFault(envP, "<fault> contains a <%s> element. " "Only <value> makes sense.", elemName); else { xmlrpc_value * faultVP; xmlrpc_parseValue(envP, maxRecursion, faultValueP, &faultVP); if (!envP->fault_occurred) { interpretFaultValue(envP, faultVP, faultCodeP, faultStringP); xmlrpc_DECREF(faultVP); } } } }
static void parseMethodNameElement(xmlrpc_env * const envP, xml_element * const nameElemP, const char ** const methodNameP) { XMLRPC_ASSERT(xmlrpc_streq(xml_element_name(nameElemP), "methodName")); if (xml_element_children_size(nameElemP) > 0) setParseFault(envP, "A <methodName> element should not have " "children. This one has %u of them.", xml_element_children_size(nameElemP)); else { const char * const cdata = xml_element_cdata(nameElemP); xmlrpc_validate_utf8(envP, cdata, strlen(cdata)); if (!envP->fault_occurred) { *methodNameP = strdup(cdata); if (*methodNameP == NULL) xmlrpc_faultf(envP, "Could not allocate memory for method name"); } } }
static void parseStruct(xmlrpc_env * const envP, unsigned int const maxRecursion, xml_element * const elemP, xmlrpc_value ** const structPP) { /*---------------------------------------------------------------------------- Parse the <struct> element 'elemP'. -----------------------------------------------------------------------------*/ xmlrpc_value * structP; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT(elemP != NULL); structP = xmlrpc_struct_new(envP); if (!envP->fault_occurred) { /* Iterate over our children, extracting key/value pairs. */ xml_element ** const members = xml_element_children(elemP); unsigned int const size = xml_element_children_size(elemP); unsigned int i; for (i = 0; i < size && !envP->fault_occurred; ++i) { const char * const elemName = xml_element_name(members[i]); if (!xmlrpc_streq(elemName, "member")) setParseFault(envP, "<%s> element found where only <member> " "makes sense", elemName); else { xmlrpc_value * keyP; xmlrpc_value * valueP; parseMember(envP, members[i], maxRecursion, &keyP, &valueP); if (!envP->fault_occurred) { xmlrpc_struct_set_value_v(envP, structP, keyP, valueP); xmlrpc_DECREF(keyP); xmlrpc_DECREF(valueP); } } } if (envP->fault_occurred) xmlrpc_DECREF(structP); else *structPP = structP; } }
static void parseName(xmlrpc_env * const envP, xml_element * const nameElemP, xmlrpc_value ** const valuePP) { unsigned int const childCount = xml_element_children_size(nameElemP); if (childCount > 0) setParseFault(envP, "<name> element has %u children. " "Should have none.", childCount); else { const char * const cdata = xml_element_cdata(nameElemP); size_t const cdataSize = xml_element_cdata_size(nameElemP); *valuePP = xmlrpc_string_new_lp(envP, cdataSize, cdata); } }
static xml_element * get_child_by_name (xmlrpc_env *env, xml_element *parent, char *name) { size_t child_count, i; xml_element **children; children = xml_element_children(parent); child_count = xml_element_children_size(parent); for (i = 0; i < child_count; i++) { if (xmlrpc_streq(xml_element_name(children[i]), name)) return children[i]; } xmlrpc_env_set_fault_formatted(env, XMLRPC_PARSE_ERROR, "Expected <%s> to have child <%s>", xml_element_name(parent), name); return NULL; }
static xml_element * getChildByName (xmlrpc_env * const envP, xml_element * const parentP, const char * const name) { size_t const childCount = xml_element_children_size(parentP); xml_element ** const childrenP = xml_element_children(parentP); unsigned int i; for (i = 0; i < childCount; ++i) { if (xmlrpc_streq(xml_element_name(childrenP[i]), name)) return childrenP[i]; } setParseFault(envP, "Expected <%s> to have child <%s>", xml_element_name(parentP), name); return NULL; }
static void getValueChild(xmlrpc_env * const envP, xml_element * const parentP, xml_element * * const childPP) { xml_element ** const children = xml_element_children(parentP); size_t const childCount = xml_element_children_size(parentP); xml_element * childP; unsigned int i; for (i = 0, childP = NULL; i < childCount && !childP; ++i) { if (xmlrpc_streq(xml_element_name(children[i]), "value")) childP = children[i]; } if (!childP) xmlrpc_env_set_fault(envP, XMLRPC_PARSE_ERROR, "<member> has no <value> child"); else *childPP = childP; }
static void parseMember(xmlrpc_env * const envP, xml_element * const memberP, unsigned int const maxRecursion, xmlrpc_value ** const keyPP, xmlrpc_value ** const valuePP) { unsigned int const childCount = xml_element_children_size(memberP); if (childCount != 2) setParseFault(envP, "<member> element has %u children. Only one <name> and " "one <value> make sense.", childCount); else { xml_element * nameElemP; getNameChild(envP, memberP, &nameElemP); if (!envP->fault_occurred) { parseName(envP, nameElemP, keyPP); if (!envP->fault_occurred) { xml_element * valueElemP; getValueChild(envP, memberP, &valueElemP); if (!envP->fault_occurred) xmlrpc_parseValue(envP, maxRecursion-1, valueElemP, valuePP); if (envP->fault_occurred) xmlrpc_DECREF(*keyPP); } } } }