/* performs heuristics on an xmlrpc_vector_array to determine * appropriate soap arrayType string. */ static const char* get_array_soap_type(XMLRPC_VALUE node) { XMLRPC_VALUE_TYPE_EASY type = xmlrpc_type_none; XMLRPC_VALUE xIter = XMLRPC_VectorRewind(node); int loopCount = 0; const char* soapType = TOKEN_ANY; type = XMLRPC_GetValueTypeEasy(xIter); xIter = XMLRPC_VectorNext(node); while (xIter) { /* 50 seems like a decent # of loops. That will likely * cover most cases. Any more and we start to sacrifice * performance. */ if ( (XMLRPC_GetValueTypeEasy(xIter) != type) || loopCount >= 50) { type = xmlrpc_type_none; break; } loopCount ++; xIter = XMLRPC_VectorNext(node); } switch (type) { case xmlrpc_type_none: soapType = TOKEN_ANY; break; case xmlrpc_type_empty: soapType = TOKEN_NULL; break; case xmlrpc_type_int: soapType = TOKEN_INT; break; case xmlrpc_type_double: soapType = TOKEN_DOUBLE; break; case xmlrpc_type_boolean: soapType = TOKEN_BOOLEAN; break; case xmlrpc_type_string: soapType = TOKEN_STRING; break; case xmlrpc_type_base64: soapType = TOKEN_BASE64; break; case xmlrpc_type_datetime: soapType = TOKEN_DATETIME; break; case xmlrpc_type_struct: soapType = TOKEN_STRUCT; break; case xmlrpc_type_array: soapType = TOKEN_ARRAY; break; case xmlrpc_type_mixed: soapType = TOKEN_STRUCT; break; } return soapType; }
/* this complies with system.methodSignature as defined at * http://xmlrpc.usefulinc.com/doc/sysmethodsig.html */ static XMLRPC_VALUE xi_system_method_signature_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData) { const char* method = XMLRPC_GetValueString(XMLRPC_VectorRewind(XMLRPC_RequestGetData(input))); XMLRPC_VALUE xResponse = NULL; /* lazy loading of introspection data */ check_docs_loaded(server, userData); if(method) { server_method* sm = find_method(server, method); if(sm && sm->desc) { XMLRPC_VALUE xTypesArray = XMLRPC_CreateVector(NULL, xmlrpc_vector_array); XMLRPC_VALUE xIter, xParams, xSig, xSigIter; const char* type; /* array of possible signatures. */ xResponse = XMLRPC_CreateVector(NULL, xmlrpc_vector_array); /* find first signature */ xSig = XMLRPC_VectorGetValueWithID(sm->desc, xi_token_signatures); xSigIter = XMLRPC_VectorRewind( xSig ); /* iterate through sigs */ while(xSigIter) { /* first type is the return value */ type = XMLRPC_VectorGetStringWithID(XMLRPC_VectorRewind( XMLRPC_VectorGetValueWithID(xSigIter, xi_token_returns)), xi_token_type); XMLRPC_AddValueToVector(xTypesArray, XMLRPC_CreateValueString(NULL, type ? type : type_to_str(xmlrpc_none, 0), 0)); /* the rest are parameters */ xParams = XMLRPC_VectorGetValueWithID(xSigIter, xi_token_params); xIter = XMLRPC_VectorRewind(xParams); /* iter through params, adding to types array */ while(xIter) { XMLRPC_AddValueToVector(xTypesArray, XMLRPC_CreateValueString(NULL, XMLRPC_VectorGetStringWithID(xIter, xi_token_type), 0)); xIter = XMLRPC_VectorNext(xParams); } /* add types for this signature */ XMLRPC_AddValueToVector(xResponse, xTypesArray); xSigIter = XMLRPC_VectorNext( xSig ); } } } return xResponse; }
/****f* SERVER/XMLRPC_ServerAddIntrospectionData * NAME * XMLRPC_ServerAddIntrospectionData * SYNOPSIS * int XMLRPC_ServerAddIntrospectionData(XMLRPC_SERVER server, XMLRPC_VALUE desc) * FUNCTION * updates server with additional introspection data * INPUTS * server - target server * desc - introspection data, should be a struct generated by * XMLRPC_IntrospectionCreateDescription () * RESULT * int - 1 if success, else 0 * NOTES * - function will fail if neither typeList nor methodList key is present in struct. * - if method or type already exists, it will be replaced. * - desc is never freed by the server. caller is responsible for cleanup. * BUGS * - horribly slow lookups. prime candidate for hash improvements. * - uglier and more complex than I like to see for API functions. * SEE ALSO * XMLRPC_ServerAddIntrospectionData () * XMLRPC_ServerRegisterIntrospectionCallback () * XMLRPC_CleanupValue () * SOURCE */ int XMLRPC_ServerAddIntrospectionData(XMLRPC_SERVER server, XMLRPC_VALUE desc) { int bSuccess = 0; if(server && desc) { XMLRPC_VALUE xNewTypes = XMLRPC_VectorGetValueWithID(desc, "typeList"); XMLRPC_VALUE xNewMethods = XMLRPC_VectorGetValueWithID(desc, "methodList"); XMLRPC_VALUE xServerTypes = XMLRPC_VectorGetValueWithID(server->xIntrospection, "typeList"); if(xNewMethods) { XMLRPC_VALUE xMethod = XMLRPC_VectorRewind(xNewMethods); while(xMethod) { const char* name = XMLRPC_VectorGetStringWithID(xMethod, xi_token_name); server_method* sm = find_method(server, name); if(sm) { if(sm->desc) { XMLRPC_CleanupValue(sm->desc); } sm->desc = XMLRPC_CopyValue(xMethod); bSuccess = 1; } xMethod = XMLRPC_VectorNext(xNewMethods); } } if(xNewTypes) { if(!xServerTypes) { if(!server->xIntrospection) { server->xIntrospection = XMLRPC_CreateVector(NULL, xmlrpc_vector_struct); } XMLRPC_AddValueToVector(server->xIntrospection, xNewTypes); bSuccess = 1; } else { XMLRPC_VALUE xIter = XMLRPC_VectorRewind(xNewTypes); while(xIter) { /* get rid of old values */ XMLRPC_VALUE xPrev = find_named_value(xServerTypes, XMLRPC_VectorGetStringWithID(xIter, xi_token_name)); if(xPrev) { XMLRPC_VectorRemoveValue(xServerTypes, xPrev); } XMLRPC_AddValueToVector(xServerTypes, xIter); bSuccess = 1; xIter = XMLRPC_VectorNext(xNewTypes); } } } } return bSuccess; }
XMLRPC_VALUE xsm_system_multicall_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData) { XMLRPC_VALUE xArray = XMLRPC_VectorRewind(XMLRPC_RequestGetData(input)); XMLRPC_VALUE xReturn = XMLRPC_CreateVector(0, xmlrpc_vector_array); if (xArray) { XMLRPC_VALUE xMethodIter = XMLRPC_VectorRewind(xArray); while (xMethodIter) { XMLRPC_REQUEST request = XMLRPC_RequestNew(); if(request) { const char* methodName = XMLRPC_VectorGetStringWithID(xMethodIter, "methodName"); XMLRPC_VALUE params = XMLRPC_VectorGetValueWithID(xMethodIter, "params"); if(methodName && params) { XMLRPC_VALUE xRandomArray = XMLRPC_CreateVector(0, xmlrpc_vector_array); XMLRPC_RequestSetMethodName(request, methodName); XMLRPC_RequestSetData(request, params); XMLRPC_RequestSetRequestType(request, xmlrpc_request_call); XMLRPC_AddValueToVector(xRandomArray, XMLRPC_ServerCallMethod(server, request, userData)); XMLRPC_AddValueToVector(xReturn, xRandomArray); } XMLRPC_RequestFree(request, 1); } xMethodIter = XMLRPC_VectorNext(xArray); } } return xReturn; }
/* * This handler takes a single parameter, which is an array containing * between 100 and 200 elements. Each of the items is a string, your handler * must return a string containing the concatenated text of the first and * last elements. */ XMLRPC_VALUE validator1_moderateSizeArrayCheck (XMLRPC_SERVER server, XMLRPC_REQUEST xRequest, void* userData) { XMLRPC_VALUE xReturn = NULL; simplestring buf; simplestring_init(&buf); if(xRequest) { XMLRPC_VALUE xArray = XMLRPC_VectorRewind(XMLRPC_RequestGetData(xRequest)); if(xArray) { XMLRPC_VALUE xIter = XMLRPC_VectorRewind(xArray), xPrev = 0; simplestring_add(&buf, XMLRPC_GetValueString(xIter)); /* TODO: Should add XMLRPC_VectorLast() call. Much more efficient */ while(xIter) { xPrev = xIter; xIter = XMLRPC_VectorNext(xArray); } simplestring_add(&buf, XMLRPC_GetValueString(xPrev)); } } xReturn = XMLRPC_CreateValueString(0, buf.str, buf.len); return xReturn; }
static void parseOptionInto( const std::string& id, XMLRPC_VALUE option, LLUserAuth::options_t& options) { std::string key; std::string val; XMLRPC_VALUE_TYPE_EASY type; XMLRPC_VALUE row = XMLRPC_VectorRewind(option); while(row) { XMLRPC_VALUE opt = XMLRPC_VectorRewind(row); LLUserAuth::response_t responses; while(opt) { key.assign(XMLRPC_GetValueID(opt)); //llinfos << "option key: " << key << llendl; type = XMLRPC_GetValueTypeEasy(opt); if(xmlrpc_type_string == type) { val.assign(XMLRPC_GetValueString(opt)); //llinfos << "string val: " << val << llendl; } else if(xmlrpc_type_int == type) { val = llformat("%d", XMLRPC_GetValueInt(opt)); //llinfos << "int val: " << val << llendl; } else if(xmlrpc_type_double == type) { val = llformat("%g", XMLRPC_GetValueDouble(opt)); //llinfos << "double val: " << val << llendl; } else { // Can't understand the type val = "???"; //llinfos << "unknown value type: " << type << llendl; } responses.insert(LLUserAuth::response_t::value_type(key, val)); opt = XMLRPC_VectorNext(row); } options.push_back(responses); row = XMLRPC_VectorNext(option); } }
/* iterates through a list of structs and finds the one with key "name" matching * needle. slow, would benefit from a struct key hash. */ static inline XMLRPC_VALUE find_named_value(XMLRPC_VALUE list, const char* needle) { XMLRPC_VALUE xIter = XMLRPC_VectorRewind(list); while(xIter) { const char* name = XMLRPC_VectorGetStringWithID(xIter, xi_token_name); if(name && !strcmp(name, needle)) { return xIter; } xIter = XMLRPC_VectorNext(list); } return NULL; }
// STATIC ProtocolUtilities::BuddyListPtr BuddyListParser::ExtractBuddyListFromXMLRPCReply(XmlRpcEpi &call) { XmlRpcCall *xmlrpcCall = call.GetXMLRPCCall(); if (!xmlrpcCall) throw XmlRpcException("Failed to read buddy list, no XMLRPC Reply to read!"); XMLRPC_REQUEST request = xmlrpcCall->GetReply(); if (!request) throw XmlRpcException("Failed to read buddy list, no XMLRPC Reply to read!"); XMLRPC_VALUE result = XMLRPC_RequestGetData(request); if (!result) throw XmlRpcException("Failed to read buddy list, the XMLRPC Reply did not contain any data!"); XMLRPC_VALUE buddy_list_node = XMLRPC_VectorGetValueWithID(result, "buddy-list"); if (!buddy_list_node || XMLRPC_GetValueType(buddy_list_node) != xmlrpc_vector) throw XmlRpcException("Failed to read buddy list, buddy-list in the reply was not properly formed!"); ProtocolUtilities::BuddyListPtr buddy_list = ProtocolUtilities::BuddyListPtr(new ProtocolUtilities::BuddyList()); XMLRPC_VALUE item = XMLRPC_VectorRewind(buddy_list_node); while(item) { XMLRPC_VALUE_TYPE type = XMLRPC_GetValueType(item); if (type == xmlrpc_vector) // xmlrpc-epi handles structs as arrays. { RexUUID id; int rights_given = 0; int rights_has = 0; XMLRPC_VALUE val = XMLRPC_VectorGetValueWithID(item, "buddy_id"); if (val && XMLRPC_GetValueType(val) == xmlrpc_string) id.FromString( XMLRPC_GetValueString(val) ); val = XMLRPC_VectorGetValueWithID(item, "buddy_rights_given"); if (val && XMLRPC_GetValueType(val) == xmlrpc_type_int) rights_given = XMLRPC_GetValueInt(val); val = XMLRPC_VectorGetValueWithID(item, "buddy_rights_has"); if (val && XMLRPC_GetValueType(val) == xmlrpc_type_int) rights_has = XMLRPC_GetValueInt(val); ProtocolUtilities::Buddy *buddy = new ProtocolUtilities::Buddy(id, rights_given, rights_has); buddy_list->AddBuddy(buddy); } item = XMLRPC_VectorNext(buddy_list_node); } return buddy_list; }
/* system.describeMethods() callback */ static XMLRPC_VALUE xi_system_describe_methods_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData) { XMLRPC_VALUE xParams = XMLRPC_VectorRewind(XMLRPC_RequestGetData(input)); XMLRPC_VALUE xResponse = XMLRPC_CreateVector(NULL, xmlrpc_vector_struct); XMLRPC_VALUE xMethodList = XMLRPC_CreateVector("methodList", xmlrpc_vector_array); XMLRPC_VALUE xTypeList = NULL; int bAll = 1; /* lazy loading of introspection data */ check_docs_loaded(server, userData); xTypeList = XMLRPC_VectorGetValueWithID(server->xIntrospection, "typeList"); XMLRPC_AddValueToVector(xResponse, xTypeList); XMLRPC_AddValueToVector(xResponse, xMethodList); /* check if we have any param */ if(xParams) { /* check if string or vector (1 or n) */ XMLRPC_VALUE_TYPE type = XMLRPC_GetValueType(xParams); if(type == xmlrpc_string) { /* just one. spit it out. */ describe_method(server, xMethodList, XMLRPC_GetValueString(xParams)); bAll = 0; } else if(type == xmlrpc_vector) { /* multiple. spit all out */ XMLRPC_VALUE xIter = XMLRPC_VectorRewind(xParams); while(xIter) { describe_method(server, xMethodList, XMLRPC_GetValueString(xIter)); xIter = XMLRPC_VectorNext(xParams); } bAll = 0; } } /* otherwise, default to sending all methods */ if(bAll) { q_iter qi = Q_Iter_Head_F(&server->methodlist); while( qi ) { server_method* sm = Q_Iter_Get_F(qi); if(sm) { XMLRPC_AddValueToVector(xMethodList, sm->desc); } qi = Q_Iter_Next_F(qi); } } return xResponse; }
/* * This handler takes six parameters, and returns an array containing all the * parameters. */ XMLRPC_VALUE validator1_manyTypesTest (XMLRPC_SERVER server, XMLRPC_REQUEST xRequest, void* userData) { XMLRPC_VALUE xArray = XMLRPC_CreateVector(0, xmlrpc_vector_array); if(xRequest && xArray) { XMLRPC_VALUE xParams = XMLRPC_RequestGetData(xRequest); XMLRPC_VALUE xIter = XMLRPC_VectorRewind(xParams); while(xIter) { XMLRPC_AddValueToVector(xArray, XMLRPC_CopyValue(xIter)); xIter = XMLRPC_VectorNext(xParams); } } return xArray; }
XMLRPC_VALUE XMLRPC::getNextValue() { XMLRPC_VALUE params = XMLRPC_RequestGetData(xmlrpc_request); XMLRPC_VALUE param; if(doRewind) { doRewind = false; param = XMLRPC_VectorRewind(params); }else param = XMLRPC_VectorNext(params); #if BTG_EXTERNALIZATION_DEBUG BTG_NOTICE(logWrapper(), "XMLRPC::getNextValue() retrieved param of type " << XMLRPC_GetValueType(param)); #endif return param; }
/* * This handler takes a single parameter, an array of structs, each of which * contains at least three elements named moe, larry and curly, all <i4>s. * Your handler must add all the struct elements named curly and return the * result. */ XMLRPC_VALUE validator1_arrayOfStructsTest (XMLRPC_SERVER server, XMLRPC_REQUEST xRequest, void* userData) { XMLRPC_VALUE xReturn = NULL; int iCurly = 0; if(xRequest) { XMLRPC_VALUE xArray = XMLRPC_VectorRewind(XMLRPC_RequestGetData(xRequest)); if(xArray) { XMLRPC_VALUE xIter = XMLRPC_VectorRewind(xArray); while(xIter) { iCurly += XMLRPC_VectorGetIntWithID(xIter, "curly"); xIter = XMLRPC_VectorNext(xArray); } } } xReturn = XMLRPC_CreateValueInt(0, iCurly); return xReturn; }
LLXMLRPCValue LLXMLRPCValue::next() { return LLXMLRPCValue(XMLRPC_VectorNext(mV)); }
LLSD LLUserAuth::parseValues(UserAuthcode &auth_code, const std::string& key_pfx, XMLRPC_VALUE param) { auth_code = E_OK; LLSD responses; for(XMLRPC_VALUE current = XMLRPC_VectorRewind(param); current; current = XMLRPC_VectorNext(param)) { std::string key(XMLRPC_GetValueID(current)); lldebugs << "key: " << key_pfx << key << llendl; XMLRPC_VALUE_TYPE_EASY type = XMLRPC_GetValueTypeEasy(current); if(xmlrpc_type_string == type) { LLSD::String val(XMLRPC_GetValueString(current)); lldebugs << "val: " << val << llendl; responses.insert(key,val); } else if(xmlrpc_type_int == type) { LLSD::Integer val(XMLRPC_GetValueInt(current)); lldebugs << "val: " << val << llendl; responses.insert(key,val); } else if (xmlrpc_type_double == type) { LLSD::Real val(XMLRPC_GetValueDouble(current)); lldebugs << "val: " << val << llendl; responses.insert(key,val); } else if(xmlrpc_type_array == type) { // We expect this to be an array of submaps. Walk the array, // recursively parsing each submap and collecting them. LLSD array; int i = 0; // for descriptive purposes for (XMLRPC_VALUE row = XMLRPC_VectorRewind(current); row; row = XMLRPC_VectorNext(current), ++i) { // Recursive call. For the lower-level key_pfx, if 'key' // is "foo", pass "foo[0]:", then "foo[1]:", etc. In the // nested call, a subkey "bar" will then be logged as // "foo[0]:bar", and so forth. // Parse the scalar subkey/value pairs from this array // entry into a temp submap. Collect such submaps in 'array'. std::string key_prefix = key_pfx; array.append(parseValues(auth_code, STRINGIZE(key_pfx << key << '[' << i << "]:"), row)); } // Having collected an 'array' of 'submap's, insert that whole // 'array' as the value of this 'key'. responses.insert(key, array); } else if (xmlrpc_type_struct == type) { LLSD submap = parseValues(auth_code, STRINGIZE(key_pfx << key << ':'), current); responses.insert(key, submap); } else { // whoops - unrecognized type llwarns << "Unhandled xmlrpc type " << type << " for key " << key_pfx << key << LL_ENDL; responses.insert(key, STRINGIZE("<bad XMLRPC type " << type << '>')); auth_code = E_UNHANDLED_ERROR; } } return responses; }
// this is a c function here since it's really an implementation // detail that requires a header file just get the definition of the // parameters. LLIOPipe::EStatus stream_out(std::ostream& ostr, XMLRPC_VALUE value) { XMLRPC_VALUE_TYPE_EASY type = XMLRPC_GetValueTypeEasy(value); LLIOPipe::EStatus status = LLIOPipe::STATUS_OK; switch(type) { case xmlrpc_type_base64: { S32 len = XMLRPC_GetValueStringLen(value); const char* buf = XMLRPC_GetValueBase64(value); ostr << " b("; if((len > 0) && buf) { ostr << len << ")\""; ostr.write(buf, len); ostr << "\""; } else { ostr << "0)\"\""; } break; } case xmlrpc_type_boolean: //lldebugs << "stream_out() bool" << llendl; ostr << " " << (XMLRPC_GetValueBoolean(value) ? "true" : "false"); break; case xmlrpc_type_datetime: ostr << " d\"" << XMLRPC_GetValueDateTime_ISO8601(value) << "\""; break; case xmlrpc_type_double: ostr << " r" << XMLRPC_GetValueDouble(value); //lldebugs << "stream_out() double" << XMLRPC_GetValueDouble(value) // << llendl; break; case xmlrpc_type_int: ostr << " i" << XMLRPC_GetValueInt(value); //lldebugs << "stream_out() integer:" << XMLRPC_GetValueInt(value) // << llendl; break; case xmlrpc_type_string: //lldebugs << "stream_out() string: " << str << llendl; ostr << " s(" << XMLRPC_GetValueStringLen(value) << ")'" << XMLRPC_GetValueString(value) << "'"; break; case xmlrpc_type_array: // vector case xmlrpc_type_mixed: // vector { //lldebugs << "stream_out() array" << llendl; ostr << " ["; U32 needs_comma = 0; XMLRPC_VALUE current = XMLRPC_VectorRewind(value); while(current && (LLIOPipe::STATUS_OK == status)) { if(needs_comma++) ostr << ","; status = stream_out(ostr, current); current = XMLRPC_VectorNext(value); } ostr << "]"; break; } case xmlrpc_type_struct: // still vector { //lldebugs << "stream_out() struct" << llendl; ostr << " {"; std::string name; U32 needs_comma = 0; XMLRPC_VALUE current = XMLRPC_VectorRewind(value); while(current && (LLIOPipe::STATUS_OK == status)) { if(needs_comma++) ostr << ","; name.assign(XMLRPC_GetValueID(current)); ostr << "'" << LLSDNotationFormatter::escapeString(name) << "':"; status = stream_out(ostr, current); current = XMLRPC_VectorNext(value); } ostr << "}"; break; } case xmlrpc_type_empty: case xmlrpc_type_none: default: status = LLIOPipe::STATUS_ERROR; llwarns << "Found an empty xmlrpc type.." << llendl; // not much we can do here... break; }; return status; }
xml_element* XMLRPC_to_xml_element_worker(XMLRPC_VALUE current_vector, XMLRPC_VALUE node, XMLRPC_REQUEST_TYPE request_type, int depth) { #define BUF_SIZE 512 xml_element* root = NULL; if (node) { char buf[BUF_SIZE]; XMLRPC_VALUE_TYPE type = XMLRPC_GetValueType(node); XMLRPC_VECTOR_TYPE vtype = XMLRPC_GetVectorType(node); xml_element* elem_val = xml_elem_new(); /* special case for when root element is not an array */ if (depth == 0 && !(type == xmlrpc_vector && vtype == xmlrpc_vector_array && request_type == xmlrpc_request_call) ) { int bIsFault = (vtype == xmlrpc_vector_struct && XMLRPC_VectorGetValueWithID(node, ELEM_FAULTCODE)); xml_element* next_el = XMLRPC_to_xml_element_worker(NULL, node, request_type, depth + 1); if (next_el) { Q_PushTail(&elem_val->children, next_el); } elem_val->name = strdup(bIsFault ? ELEM_FAULT : ELEM_PARAMS); } else { switch (type) { case xmlrpc_empty: /* treat null value as empty string in xmlrpc. */ case xmlrpc_string: elem_val->name = strdup(ELEM_STRING); simplestring_addn(&elem_val->text, XMLRPC_GetValueString(node), XMLRPC_GetValueStringLen(node)); break; case xmlrpc_int: elem_val->name = strdup(ELEM_INT); snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueInt(node)); simplestring_add(&elem_val->text, buf); break; case xmlrpc_boolean: elem_val->name = strdup(ELEM_BOOLEAN); snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueBoolean(node)); simplestring_add(&elem_val->text, buf); break; case xmlrpc_double: elem_val->name = strdup(ELEM_DOUBLE); snprintf(buf, BUF_SIZE, "%f", XMLRPC_GetValueDouble(node)); simplestring_add(&elem_val->text, buf); break; case xmlrpc_datetime: elem_val->name = strdup(ELEM_DATETIME); simplestring_add(&elem_val->text, XMLRPC_GetValueDateTime_ISO8601(node)); break; case xmlrpc_base64: { struct buffer_st buf; elem_val->name = strdup(ELEM_BASE64); base64_encode(&buf, XMLRPC_GetValueBase64(node), XMLRPC_GetValueStringLen(node)); simplestring_addn(&elem_val->text, buf.data, buf.offset ); buffer_delete(&buf); } break; case xmlrpc_vector: { XMLRPC_VECTOR_TYPE my_type = XMLRPC_GetVectorType(node); XMLRPC_VALUE xIter = XMLRPC_VectorRewind(node); xml_element* root_vector_elem = elem_val; switch (my_type) { case xmlrpc_vector_array: { if(depth == 0) { elem_val->name = strdup(ELEM_PARAMS); } else { /* Hi my name is Dave and I like to make things as confusing * as possible, thus I will throw in this 'data' element * where it absolutely does not belong just so that people * cannot code arrays and structs in a similar and straight * forward manner. Have a good day. * * GRRRRRRRRR! */ xml_element* data = xml_elem_new(); data->name = strdup(ELEM_DATA); elem_val->name = strdup(ELEM_ARRAY); Q_PushTail(&elem_val->children, data); root_vector_elem = data; } } break; case xmlrpc_vector_mixed: /* not officially supported */ case xmlrpc_vector_struct: elem_val->name = strdup(ELEM_STRUCT); break; default: break; } /* recurse through sub-elements */ while ( xIter ) { xml_element* next_el = XMLRPC_to_xml_element_worker(node, xIter, request_type, depth + 1); if (next_el) { Q_PushTail(&root_vector_elem->children, next_el); } xIter = XMLRPC_VectorNext(node); } } break; default: break; } } { XMLRPC_VECTOR_TYPE vtype = XMLRPC_GetVectorType(current_vector); if (depth == 1) { xml_element* value = xml_elem_new(); value->name = strdup(ELEM_VALUE); /* yet another hack for the "fault" crap */ if (XMLRPC_VectorGetValueWithID(node, ELEM_FAULTCODE)) { root = value; } else { xml_element* param = xml_elem_new(); param->name = strdup(ELEM_PARAM); Q_PushTail(¶m->children, value); root = param; } Q_PushTail(&value->children, elem_val); } else if (vtype == xmlrpc_vector_struct || vtype == xmlrpc_vector_mixed) { xml_element* member = xml_elem_new(); xml_element* name = xml_elem_new(); xml_element* value = xml_elem_new(); member->name = strdup(ELEM_MEMBER); name->name = strdup(ELEM_NAME); value->name = strdup(ELEM_VALUE); simplestring_add(&name->text, XMLRPC_GetValueID(node)); Q_PushTail(&member->children, name); Q_PushTail(&member->children, value); Q_PushTail(&value->children, elem_val); root = member; } else if (vtype == xmlrpc_vector_array) { xml_element* value = xml_elem_new(); value->name = strdup(ELEM_VALUE); Q_PushTail(&value->children, elem_val); root = value; } else if (vtype == xmlrpc_vector_none) { /* no parent. non-op */ root = elem_val; } else { xml_element* value = xml_elem_new(); value->name = strdup(ELEM_VALUE); Q_PushTail(&value->children, elem_val); root = value; } } } return root; }
LLUserAuth::UserAuthcode LLUserAuth::parseResponse() { // The job of this function is to parse sCurlDownloadArea and // extract every member into either the mResponses or // mOptions. For now, we will only be looking at mResponses, which // will all be string => string pairs. UserAuthcode rv = E_UNHANDLED_ERROR; XMLRPC_REQUEST response = mTransaction->response(); if(!response) return rv; // clear out any old parsing mResponses.clear(); mOptions.clear(); // Now, parse everything std::string key; std::string val; XMLRPC_VALUE param = NULL; XMLRPC_VALUE current = NULL; XMLRPC_VALUE_TYPE_EASY type; param = XMLRPC_RequestGetData(response); if(!param) goto exit; current = XMLRPC_VectorRewind(param); while(current) { key.assign(XMLRPC_GetValueID(current)); lldebugs << "key: " << key << llendl; type = XMLRPC_GetValueTypeEasy(current); if(xmlrpc_type_string == type) { val.assign(XMLRPC_GetValueString(current)); lldebugs << "val: " << val << llendl; mResponses.insert(response_t::value_type(key, val)); } else if(xmlrpc_type_int == type) { val = llformat( "%d", XMLRPC_GetValueInt(current)); lldebugs << "val: " << val << llendl; mResponses.insert(response_t::value_type(key, val)); } else if(xmlrpc_type_array == type) { options_t options; parseOptionInto(key, current, options); mOptions.insert(all_options_t::value_type(key, options)); } else { // whoops - bad response llwarns << "Unhandled xmlrpc type, key, value: " << type << " " << key << " " << val << "." << llendl; rv = E_UNHANDLED_ERROR; break; } current = XMLRPC_VectorNext(param); rv = E_OK; } exit: return rv; }
/* translates data structures to soap/xml. recursive */ xml_element* SOAP_to_xml_element_worker(XMLRPC_REQUEST request, XMLRPC_VALUE node) { #define BUF_SIZE 128 xml_element* elem_val = NULL; if (node) { int bFreeNode = 0; /* sometimes we may need to free 'node' variable */ char buf[BUF_SIZE]; XMLRPC_VALUE_TYPE_EASY type = XMLRPC_GetValueTypeEasy(node); char* pName = NULL, *pAttrType = NULL; /* create our return value element */ elem_val = xml_elem_new(); switch (type) { case xmlrpc_type_struct: case xmlrpc_type_mixed: case xmlrpc_type_array: if (type == xmlrpc_type_array) { /* array's are _very_ special in soap. TODO: Should handle sparse/partial arrays here. */ /* determine soap array type. */ const char* type = get_array_soap_type(node); xml_element_attr* attr_array_type = NULL; /* specify array kids type and array size. */ snprintf(buf, sizeof(buf), "%s[%i]", type, XMLRPC_VectorSize(node)); attr_array_type = new_attr(TOKEN_ARRAY_TYPE, buf); Q_PushTail(&elem_val->attrs, attr_array_type); pAttrType = TOKEN_ARRAY; } /* check for fault, which is a rather special case. (can't these people design anything consistent/simple/elegant?) */ else if (type == xmlrpc_type_struct) { int fault_type = get_fault_type(node); if (fault_type) { if (fault_type == 1) { /* gen fault from xmlrpc style fault codes notice that we get a new node, which must be freed herein. */ node = gen_fault_xmlrpc(node, elem_val); bFreeNode = 1; } pName = TOKEN_FAULT; } } { /* recurse through sub-elements */ XMLRPC_VALUE xIter = XMLRPC_VectorRewind(node); while ( xIter ) { xml_element* next_el = SOAP_to_xml_element_worker(request, xIter); if (next_el) { Q_PushTail(&elem_val->children, next_el); } xIter = XMLRPC_VectorNext(node); } } break; /* handle scalar types */ case xmlrpc_type_empty: pAttrType = TOKEN_NULL; break; case xmlrpc_type_string: pAttrType = TOKEN_STRING; simplestring_addn(&elem_val->text, XMLRPC_GetValueString(node), XMLRPC_GetValueStringLen(node)); break; case xmlrpc_type_int: pAttrType = TOKEN_INT; snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueInt(node)); simplestring_add(&elem_val->text, buf); break; case xmlrpc_type_boolean: pAttrType = TOKEN_BOOLEAN; snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueBoolean(node)); simplestring_add(&elem_val->text, buf); break; case xmlrpc_type_double: pAttrType = TOKEN_DOUBLE; snprintf(buf, BUF_SIZE, "%f", XMLRPC_GetValueDouble(node)); simplestring_add(&elem_val->text, buf); break; case xmlrpc_type_datetime: { time_t tt = XMLRPC_GetValueDateTime(node); struct tm *tm = localtime (&tt); pAttrType = TOKEN_DATETIME; if(strftime (buf, BUF_SIZE, "%Y-%m-%dT%H:%M:%SZ", tm)) { simplestring_add(&elem_val->text, buf); } } break; case xmlrpc_type_base64: { struct buffer_st buf; pAttrType = TOKEN_BASE64; base64_encode_xmlrpc(&buf, XMLRPC_GetValueBase64(node), XMLRPC_GetValueStringLen(node)); simplestring_addn(&elem_val->text, buf.data, buf.offset ); buffer_delete(&buf); } break; break; default: break; } /* determining element's name is a bit tricky, due to soap semantics. */ if (!pName) { /* if the value's type is known... */ if (pAttrType) { /* see if it has an id (key). If so, use that as name, and type as an attribute. */ pName = (char*)XMLRPC_GetValueID(node); if (pName) { Q_PushTail(&elem_val->attrs, new_attr(TOKEN_TYPE, pAttrType)); } /* otherwise, use the type as the name. */ else { pName = pAttrType; } } /* if the value's type is not known... (a rare case?) */ else { /* see if it has an id (key). otherwise, default to generic "item" */ pName = (char*)XMLRPC_GetValueID(node); if (!pName) { pName = "item"; } } } elem_val->name = strdup(pName); /* cleanup */ if (bFreeNode) { XMLRPC_CleanupValue(node); } } return elem_val; }
LLIOPipe::EStatus LLFilterXMLRPCRequest2LLSD::process_impl( const LLChannelDescriptors& channels, buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump) { LLFastTimer t(FTM_PROCESS_XMLRPC2LLSD_REQUEST); PUMP_DEBUG; if(!eos) return STATUS_BREAK; if(!buffer) return STATUS_ERROR; PUMP_DEBUG; // *FIX: This technique for reading data is far from optimal. We // need to have some kind of istream interface into the xml // parser... S32 bytes = buffer->countAfter(channels.in(), NULL); if(!bytes) return STATUS_ERROR; char* buf = new char[bytes + 1]; buf[bytes] = '\0'; buffer->readAfter(channels.in(), NULL, (U8*)buf, bytes); //lldebugs << "xmlrpc request: " << buf << llendl; // Check the value in the buffer. XMLRPC_REQUEST_FromXML will report a error code 4 if // values that are less than 0x20 are passed to it, except // 0x09: Horizontal tab; 0x0a: New Line; 0x0d: Carriage U8* cur_pBuf = (U8*)buf; U8 cur_char; for (S32 i=0; i<bytes; i++) { cur_char = *cur_pBuf; if ( cur_char < 0x20 && 0x09 != cur_char && 0x0a != cur_char && 0x0d != cur_char ) { *cur_pBuf = '?'; } ++cur_pBuf; } PUMP_DEBUG; XMLRPC_REQUEST request = XMLRPC_REQUEST_FromXML( buf, bytes, NULL); if(!request) { llwarns << "XML -> SD Request process parse error." << llendl; delete[] buf; return STATUS_ERROR; } PUMP_DEBUG; LLBufferStream stream(channels, buffer.get()); stream.precision(DEFAULT_PRECISION); const char* name = XMLRPC_RequestGetMethodName(request); stream << LLSDRPC_REQUEST_HEADER_1 << (name ? name : "") << LLSDRPC_REQUEST_HEADER_2; XMLRPC_VALUE param = XMLRPC_RequestGetData(request); if(param) { PUMP_DEBUG; S32 size = XMLRPC_VectorSize(param); if(size > 1) { // if there are multiple parameters, stuff the values into // an array so that the next step in the chain can read them. stream << "["; } XMLRPC_VALUE current = XMLRPC_VectorRewind(param); bool needs_comma = false; while(current) { if(needs_comma) { stream << ","; } needs_comma = true; stream_out(stream, current); current = XMLRPC_VectorNext(param); } if(size > 1) { // close the array stream << "]"; } } stream << LLSDRPC_REQUEST_FOOTER << std::flush; XMLRPC_RequestFree(request, 1); delete[] buf; PUMP_DEBUG; return STATUS_DONE; }
xml_element* DANDARPC_to_xml_element_worker(XMLRPC_REQUEST request, XMLRPC_VALUE node) { #define BUF_SIZE 512 xml_element* root = NULL; if(node) { char buf[BUF_SIZE]; const char* id = XMLRPC_GetValueID(node); XMLRPC_VALUE_TYPE type = XMLRPC_GetValueType(node); XMLRPC_REQUEST_OUTPUT_OPTIONS output = XMLRPC_RequestGetOutputOptions(request); int bNoAddType = (type == xmlrpc_string && request && output && output->xml_elem_opts.verbosity == xml_elem_no_white_space); xml_element* elem_val = xml_elem_new(); const char* pAttrType = NULL; xml_element_attr* attr_type = bNoAddType ? NULL : emalloc(sizeof(xml_element_attr)); if(attr_type) { attr_type->key = estrdup(ATTR_TYPE); attr_type->val = 0; Q_PushTail(&elem_val->attrs, attr_type); } elem_val->name = (type == xmlrpc_vector) ? estrdup(ATTR_VECTOR) : estrdup(ATTR_SCALAR); if(id && *id) { xml_element_attr* attr_id = emalloc(sizeof(xml_element_attr)); if(attr_id) { attr_id->key = estrdup(ATTR_ID); attr_id->val = estrdup(id); Q_PushTail(&elem_val->attrs, attr_id); } } switch(type) { case xmlrpc_string: pAttrType = ATTR_STRING; simplestring_addn(&elem_val->text, XMLRPC_GetValueString(node), XMLRPC_GetValueStringLen(node)); break; case xmlrpc_int: pAttrType = ATTR_INT; snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueInt(node)); simplestring_add(&elem_val->text, buf); break; case xmlrpc_boolean: pAttrType = ATTR_BOOLEAN; snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueBoolean(node)); simplestring_add(&elem_val->text, buf); break; case xmlrpc_double: pAttrType = ATTR_DOUBLE; snprintf(buf, BUF_SIZE, "%f", XMLRPC_GetValueDouble(node)); simplestring_add(&elem_val->text, buf); break; case xmlrpc_datetime: pAttrType = ATTR_DATETIME; simplestring_add(&elem_val->text, XMLRPC_GetValueDateTime_ISO8601(node)); break; case xmlrpc_base64: { struct buffer_st buf; pAttrType = ATTR_BASE64; base64_encode_xmlrpc(&buf, XMLRPC_GetValueBase64(node), XMLRPC_GetValueStringLen(node)); simplestring_addn(&elem_val->text, buf.data, buf.offset ); buffer_delete(&buf); } break; case xmlrpc_vector: { XMLRPC_VECTOR_TYPE my_type = XMLRPC_GetVectorType(node); XMLRPC_VALUE xIter = XMLRPC_VectorRewind(node); switch(my_type) { case xmlrpc_vector_array: pAttrType = ATTR_ARRAY; break; case xmlrpc_vector_mixed: pAttrType = ATTR_MIXED; break; case xmlrpc_vector_struct: pAttrType = ATTR_STRUCT; break; default: break; } /* recurse through sub-elements */ while( xIter ) { xml_element* next_el = DANDARPC_to_xml_element_worker(request, xIter); if(next_el) { Q_PushTail(&elem_val->children, next_el); } xIter = XMLRPC_VectorNext(node); } } break; default: break; } if(pAttrType && attr_type && !bNoAddType) { attr_type->val = estrdup(pAttrType); } root = elem_val; } return root; }