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)); }
void xmlrpc_parse_response2(xmlrpc_env * const envP, const char * const xmlData, size_t const xmlDataLen, xmlrpc_value ** const resultPP, int * const faultCodeP, const char ** const faultStringP) { /*---------------------------------------------------------------------------- Given some XML text, attempt to parse it as an XML-RPC response. If the response is a regular, valid response, return a new reference to the appropriate value as *resultP and return NULL as *faultStringP and nothing as *faultCodeP. If the response is valid, but indicates a failure of the RPC, return the fault string in newly malloc'ed space as *faultStringP and the fault code as *faultCodeP and nothing as *resultP. If the XML text is not a valid response or something prevents us from parsing it, return a description of the error as *envP and nothing else. -----------------------------------------------------------------------------*/ xml_element * response; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT(xmlData != NULL); /* SECURITY: Last-ditch attempt to make sure our content length is legal. ** XXX - This check occurs too late to prevent an attacker from creating ** an enormous memory block, so you should try to enforce it ** *before* reading any data off the network. */ if (xmlDataLen > xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID)) xmlrpc_env_set_fault_formatted( envP, XMLRPC_LIMIT_EXCEEDED_ERROR, "XML-RPC response too large. Our limit is %u characters. " "We got %u characters", xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID), xmlDataLen); else { xmlrpc_env env; xmlrpc_env_init(&env); xml_parse(&env, xmlData, xmlDataLen, &response); if (env.fault_occurred) setParseFault(envP, "Not valid XML. %s", env.fault_string); else { /* Pick apart and verify our structure. */ if (xmlrpc_streq(xml_element_name(response), "methodResponse")) { parseMethodResponseElt(envP, response, resultPP, faultCodeP, faultStringP); } else setParseFault(envP, "XML-RPC response must consist of a " "<methodResponse> element. " "This has a <%s> instead.", xml_element_name(response)); xml_element_free(response); } xmlrpc_env_clean(&env); } }
static void parseCallXml(xmlrpc_env * const envP, const char * const xmlData, size_t const xmlDataLen, xml_element ** const callElemPP) { /*---------------------------------------------------------------------------- Parse the XML of an XML-RPC call. -----------------------------------------------------------------------------*/ xml_element * callElemP; xmlrpc_env env; xmlrpc_env_init(&env); xml_parse(&env, xmlData, xmlDataLen, &callElemP); if (env.fault_occurred) xmlrpc_env_set_fault_formatted( envP, env.fault_code, "Call is not valid XML. %s", env.fault_string); else { if (!xmlrpc_streq(xml_element_name(callElemP), "methodCall")) setParseFault(envP, "XML-RPC call should be a <methodCall> element. " "Instead, we have a <%s> element.", xml_element_name(callElemP)); if (envP->fault_occurred) xml_element_free(callElemP); } *callElemPP = callElemP; xmlrpc_env_clean(&env); }
void xmlrpc_parse_value_xml(xmlrpc_env * const envP, const char * const xmlData, size_t const xmlDataLen, xmlrpc_value ** const valuePP) { /*---------------------------------------------------------------------------- Compute the xmlrpc_value represented by the XML document 'xmlData' (of length 'xmlDataLen' characters), which must consist of a single <value> element. Return that xmlrpc_value. We call convert_array() and convert_struct(), which may ultimately call us recursively. Don't recurse any more than 'maxRecursion' times. This isn't generally useful in XML-RPC programs, because such programs parse a whole XML-RPC call or response document, and never see the XML text of just a <value> element. But a program may do some weird form of XML-RPC processing or just borrow Xmlrpc-c's value serialization facilities for something unrelated to XML-RPC. In any case, it makes sense to have an inverse of xmlrpc_serialize_value2(), which generates XML text from an xmlrpc_value. -----------------------------------------------------------------------------*/ xmlrpc_env env; xml_element * valueEltP; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT(xmlData != NULL); xmlrpc_env_init(&env); xml_parse(&env, xmlData, xmlDataLen, &valueEltP); if (env.fault_occurred) { setParseFault(envP, "Not valid XML. %s", env.fault_string); } else { if (xmlrpc_streq(xml_element_name(valueEltP), "value")) { unsigned int const maxRecursion = (unsigned int) xmlrpc_limit_get(XMLRPC_NESTING_LIMIT_ID); xmlrpc_parseValue(envP, maxRecursion, valueEltP, valuePP); } else setParseFault(envP, "XML-RPC value XML document must consist of " "a <value> element. This has a <%s> instead.", xml_element_name(valueEltP)); xml_element_free(valueEltP); } xmlrpc_env_clean(&env); }
Alert get_alert(XmlElement xml_alert) { Alert alert = malloc(sizeof(struct Alert)); Queue alert_info = xml_element_children(xml_alert); while (!queue_empty(alert_info)) { XmlElement el = queue_dequeue(alert_info); const char *element = xml_element_name(el); if (str_equals(element, "summary")) { alert->summary = strdup(xml_element_content(el)); } else if (str_equals(element, "description")) { alert->description = strdup(xml_element_content(el)); } else if (str_equals(element, "location")) { alert->location = strdup(xml_element_content(el)); } free_xml_element(el); } destroy_queue(alert_info); return alert; }// End of get_alert method
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 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 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 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 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 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 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 parseParamsElement(xmlrpc_env * const envP, const xml_element * const paramsElementP, xmlrpc_value ** const resultPP) { xmlrpc_value * paramsVP; xmlrpc_env env; xmlrpc_env_init(&env); XMLRPC_ASSERT(xmlrpc_streq(xml_element_name(paramsElementP), "params")); paramsVP = convertParams(envP, paramsElementP); if (!envP->fault_occurred) { int arraySize; xmlrpc_env sizeEnv; XMLRPC_ASSERT_ARRAY_OK(paramsVP); xmlrpc_env_init(&sizeEnv); arraySize = xmlrpc_array_size(&sizeEnv, paramsVP); /* Since it's a valid array, as asserted above, can't fail */ XMLRPC_ASSERT(!sizeEnv.fault_occurred); if (arraySize != 1) setParseFault(envP, "Contains %d items. It should have 1.", arraySize); else { xmlrpc_array_read_item(envP, paramsVP, 0, resultPP); } xmlrpc_DECREF(paramsVP); xmlrpc_env_clean(&sizeEnv); } if (env.fault_occurred) xmlrpc_env_set_fault_formatted( envP, env.fault_code, "Invalid <params> element. %s", env.fault_string); xmlrpc_env_clean(&env); }
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 parseArrayDataChild(xmlrpc_env * const envP, xml_element * const childP, unsigned int const maxRecursion, xmlrpc_value * const arrayP) { const char * const elemName = xml_element_name(childP); if (!xmlrpc_streq(elemName, "value")) setParseFault(envP, "<data> element has <%s> child. " "Only <value> makes sense.", elemName); else { xmlrpc_value * itemP; xmlrpc_parseValue(envP, maxRecursion-1, childP, &itemP); if (!envP->fault_occurred) { xmlrpc_array_append_item(envP, arrayP, itemP); xmlrpc_DECREF(itemP); } } }
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"); } } }