00001
00078 #include "linden_common.h"
00079 #include "llfiltersd2xmlrpc.h"
00080
00081 #include <sstream>
00082 #include <iterator>
00083 #include <xmlrpc-epi/xmlrpc.h>
00084 #include "apr-1/apr_base64.h"
00085
00086 #include "llbuffer.h"
00087 #include "llbufferstream.h"
00088 #include "llmemorystream.h"
00089 #include "llsd.h"
00090 #include "llsdserialize.h"
00091 #include "lluuid.h"
00092
00093
00094
00095
00099 static const char XML_HEADER[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
00100 static const char XMLRPC_REQUEST_HEADER_1[] = "<methodCall><methodName>";
00101 static const char XMLRPC_REQUEST_HEADER_2[] = "</methodName><params>";
00102 static const char XMLRPC_REQUEST_FOOTER[] = "</params></methodCall>";
00103 static const char XMLRPC_METHOD_RESPONSE_HEADER[] = "<methodResponse>";
00104 static const char XMLRPC_METHOD_RESPONSE_FOOTER[] = "</methodResponse>";
00105 static const char XMLRPC_RESPONSE_HEADER[] = "<params><param>";
00106 static const char XMLRPC_RESPONSE_FOOTER[] = "</param></params>";
00107 static const char XMLRPC_FAULT_1[] = "<fault><value><struct><member><name>faultCode</name><value><int>";
00108 static const char XMLRPC_FAULT_2[] = "</int></value></member><member><name>faultString</name><value><string>";
00109 static const char XMLRPC_FAULT_3[] = "</string></value></member></struct></value></fault>";
00110 static const char LLSDRPC_RESPONSE_HEADER[] = "{'response':";
00111 static const char LLSDRPC_RESPONSE_FOOTER[] = "}";
00112 const char LLSDRPC_REQUEST_HEADER_1[] = "{'method':'";
00113 const char LLSDRPC_REQUEST_HEADER_2[] = "', 'parameter': ";
00114 const char LLSDRPC_REQUEST_FOOTER[] = "}";
00115 static const char LLSDRPC_FAULT_HADER_1[] = "{ 'fault': {'code':i";
00116 static const char LLSDRPC_FAULT_HADER_2[] = ", 'description':";
00117 static const char LLSDRPC_FAULT_FOOTER[] = "} }";
00118 static const S32 DEFAULT_PRECISION = 20;
00119
00123 LLFilterSD2XMLRPC::LLFilterSD2XMLRPC()
00124 {
00125 }
00126
00127 LLFilterSD2XMLRPC::~LLFilterSD2XMLRPC()
00128 {
00129 }
00130
00131 std::string xml_escape_string(const std::string& in)
00132 {
00133 std::ostringstream out;
00134 std::string::const_iterator it = in.begin();
00135 std::string::const_iterator end = in.end();
00136 for(; it != end; ++it)
00137 {
00138 switch((*it))
00139 {
00140 case '<':
00141 out << "<";
00142 break;
00143 case '>':
00144 out << ">";
00145 break;
00146 case '&':
00147 out << "&";
00148 break;
00149 case '\'':
00150 out << "'";
00151 break;
00152 case '"':
00153 out << """;
00154 break;
00155 default:
00156 out << (*it);
00157 break;
00158 }
00159 }
00160 return out.str();
00161 }
00162
00163 void LLFilterSD2XMLRPC::streamOut(std::ostream& ostr, const LLSD& sd)
00164 {
00165 ostr << "<value>";
00166 switch(sd.type())
00167 {
00168 case LLSD::TypeMap:
00169 {
00170 #if LL_SPEW_STREAM_OUT_DEBUGGING
00171 llinfos << "streamOut(map) BEGIN" << llendl;
00172 #endif
00173 ostr << "<struct>";
00174 if(ostr.fail())
00175 {
00176 llinfos << "STREAM FAILURE writing struct" << llendl;
00177 }
00178 LLSD::map_const_iterator it = sd.beginMap();
00179 LLSD::map_const_iterator end = sd.endMap();
00180 for(; it != end; ++it)
00181 {
00182 ostr << "<member><name>" << xml_escape_string((*it).first)
00183 << "</name>";
00184 streamOut(ostr, (*it).second);
00185 if(ostr.fail())
00186 {
00187 llinfos << "STREAM FAILURE writing '" << (*it).first
00188 << "' with sd type " << (*it).second.type() << llendl;
00189 }
00190 ostr << "</member>";
00191 }
00192 ostr << "</struct>";
00193 #if LL_SPEW_STREAM_OUT_DEBUGGING
00194 llinfos << "streamOut(map) END" << llendl;
00195 #endif
00196 break;
00197 }
00198 case LLSD::TypeArray:
00199 {
00200 #if LL_SPEW_STREAM_OUT_DEBUGGING
00201 llinfos << "streamOut(array) BEGIN" << llendl;
00202 #endif
00203 ostr << "<array><data>";
00204 LLSD::array_const_iterator it = sd.beginArray();
00205 LLSD::array_const_iterator end = sd.endArray();
00206 for(; it != end; ++it)
00207 {
00208 streamOut(ostr, *it);
00209 if(ostr.fail())
00210 {
00211 llinfos << "STREAM FAILURE writing array element sd type "
00212 << (*it).type() << llendl;
00213 }
00214 }
00215 #if LL_SPEW_STREAM_OUT_DEBUGGING
00216 llinfos << "streamOut(array) END" << llendl;
00217 #endif
00218 ostr << "</data></array>";
00219 break;
00220 }
00221 case LLSD::TypeUndefined:
00222
00223 case LLSD::TypeBoolean:
00224 #if LL_SPEW_STREAM_OUT_DEBUGGING
00225 llinfos << "streamOut(bool)" << llendl;
00226 #endif
00227 ostr << "<boolean>" << (sd.asBoolean() ? "1" : "0") << "</boolean>";
00228 break;
00229 case LLSD::TypeInteger:
00230 #if LL_SPEW_STREAM_OUT_DEBUGGING
00231 llinfos << "streamOut(int)" << llendl;
00232 #endif
00233 ostr << "<i4>" << sd.asInteger() << "</i4>";
00234 break;
00235 case LLSD::TypeReal:
00236 #if LL_SPEW_STREAM_OUT_DEBUGGING
00237 llinfos << "streamOut(real)" << llendl;
00238 #endif
00239 ostr << "<double>" << sd.asReal() << "</double>";
00240 break;
00241 case LLSD::TypeString:
00242 #if LL_SPEW_STREAM_OUT_DEBUGGING
00243 llinfos << "streamOut(string)" << llendl;
00244 #endif
00245 ostr << "<string>" << xml_escape_string(sd.asString()) << "</string>";
00246 break;
00247 case LLSD::TypeUUID:
00248 #if LL_SPEW_STREAM_OUT_DEBUGGING
00249 llinfos << "streamOut(uuid)" << llendl;
00250 #endif
00251
00252 ostr << "<string>" << sd.asString() << "</string>";
00253 break;
00254 case LLSD::TypeURI:
00255 {
00256 #if LL_SPEW_STREAM_OUT_DEBUGGING
00257 llinfos << "streamOut(uri)" << llendl;
00258 #endif
00259
00260 ostr << "<string>" << xml_escape_string(sd.asString()) << "</string>";
00261 break;
00262 }
00263 case LLSD::TypeBinary:
00264 {
00265 #if LL_SPEW_STREAM_OUT_DEBUGGING
00266 llinfos << "streamOut(binary)" << llendl;
00267 #endif
00268
00269
00270 ostr << "<base64>";
00271 LLSD::Binary buffer = sd.asBinary();
00272 if(!buffer.empty())
00273 {
00274
00275 int b64_buffer_length = apr_base64_encode_len(buffer.size());
00276 char* b64_buffer = new char[b64_buffer_length];
00277 b64_buffer_length = apr_base64_encode_binary(
00278 b64_buffer,
00279 &buffer[0],
00280 buffer.size());
00281 ostr.write(b64_buffer, b64_buffer_length - 1);
00282 delete[] b64_buffer;
00283 }
00284 ostr << "</base64>";
00285 break;
00286 }
00287 case LLSD::TypeDate:
00288 #if LL_SPEW_STREAM_OUT_DEBUGGING
00289 llinfos << "streamOut(date)" << llendl;
00290 #endif
00291
00292 ostr << "<dateTime.iso8601>" << sd.asString() << "</dateTime.iso8601>";
00293 break;
00294 default:
00295
00296 llwarns << "Unhandled structured data type: " << sd.type()
00297 << llendl;
00298 break;
00299 }
00300 ostr << "</value>";
00301 }
00302
00307 LLFilterSD2XMLRPCResponse::LLFilterSD2XMLRPCResponse()
00308 {
00309 }
00310
00311 LLFilterSD2XMLRPCResponse::~LLFilterSD2XMLRPCResponse()
00312 {
00313 }
00314
00315
00316
00317 LLIOPipe::EStatus LLFilterSD2XMLRPCResponse::process_impl(
00318 const LLChannelDescriptors& channels,
00319 buffer_ptr_t& buffer,
00320 bool& eos,
00321 LLSD& context,
00322 LLPumpIO* pump)
00323 {
00324 PUMP_DEBUG;
00325
00326
00327
00328 if(!eos)
00329 {
00330 return STATUS_BREAK;
00331 }
00332
00333 PUMP_DEBUG;
00334
00335
00336 LLBufferStream stream(channels, buffer.get());
00337 stream << XML_HEADER << XMLRPC_METHOD_RESPONSE_HEADER;
00338 LLSD sd;
00339 LLSDSerialize::fromNotation(sd, stream);
00340
00341 PUMP_DEBUG;
00342 LLIOPipe::EStatus rv = STATUS_ERROR;
00343 if(sd.has("response"))
00344 {
00345 PUMP_DEBUG;
00346
00347 stream.precision(DEFAULT_PRECISION);
00348 stream << XMLRPC_RESPONSE_HEADER;
00349 streamOut(stream, sd["response"]);
00350 stream << XMLRPC_RESPONSE_FOOTER << XMLRPC_METHOD_RESPONSE_FOOTER;
00351 rv = STATUS_DONE;
00352 }
00353 else if(sd.has("fault"))
00354 {
00355 PUMP_DEBUG;
00356
00357 stream << XMLRPC_FAULT_1 << sd["fault"]["code"].asInteger()
00358 << XMLRPC_FAULT_2
00359 << xml_escape_string(sd["fault"]["description"].asString())
00360 << XMLRPC_FAULT_3 << XMLRPC_METHOD_RESPONSE_FOOTER;
00361 rv = STATUS_DONE;
00362 }
00363 else
00364 {
00365 llwarns << "Unable to determine the type of LLSD response." << llendl;
00366 }
00367 PUMP_DEBUG;
00368 return rv;
00369 }
00370
00374 LLFilterSD2XMLRPCRequest::LLFilterSD2XMLRPCRequest()
00375 {
00376 }
00377
00378 LLFilterSD2XMLRPCRequest::LLFilterSD2XMLRPCRequest(const char* method)
00379 {
00380 if(method)
00381 {
00382 mMethod.assign(method);
00383 }
00384 }
00385
00386 LLFilterSD2XMLRPCRequest::~LLFilterSD2XMLRPCRequest()
00387 {
00388 }
00389
00390
00391 LLIOPipe::EStatus LLFilterSD2XMLRPCRequest::process_impl(
00392 const LLChannelDescriptors& channels,
00393 buffer_ptr_t& buffer,
00394 bool& eos,
00395 LLSD& context,
00396 LLPumpIO* pump)
00397 {
00398
00399
00400
00401 PUMP_DEBUG;
00402 if(!eos)
00403 {
00404 llinfos << "!eos" << llendl;
00405 return STATUS_BREAK;
00406 }
00407
00408
00409 LLBufferStream stream(channels, buffer.get());
00410 LLSD sd;
00411 LLSDSerialize::fromNotation(sd, stream);
00412 if(stream.fail())
00413 {
00414 llinfos << "STREAM FAILURE reading structure data." << llendl;
00415 }
00416
00417 PUMP_DEBUG;
00418
00419
00420
00421
00422 std::string method;
00423 LLSD param_sd;
00424 if(sd.has("method") && sd.has("parameter"))
00425 {
00426 method = sd["method"].asString();
00427 param_sd = sd["parameter"];
00428 }
00429 else
00430 {
00431 method = mMethod;
00432 param_sd = sd;
00433 }
00434 if(method.empty())
00435 {
00436 llwarns << "SD -> XML Request no method found." << llendl;
00437 return STATUS_ERROR;
00438 }
00439
00440 PUMP_DEBUG;
00441
00442
00443 LLBufferStream ostream(channels, buffer.get());
00444 ostream.precision(DEFAULT_PRECISION);
00445 if(ostream.fail())
00446 {
00447 llinfos << "STREAM FAILURE setting precision" << llendl;
00448 }
00449 ostream << XML_HEADER << XMLRPC_REQUEST_HEADER_1
00450 << xml_escape_string(method) << XMLRPC_REQUEST_HEADER_2;
00451 if(ostream.fail())
00452 {
00453 llinfos << "STREAM FAILURE writing method headers" << llendl;
00454 }
00455 switch(param_sd.type())
00456 {
00457 case LLSD::TypeMap:
00458
00459
00460
00461
00462 ostream << "<param>";
00463 streamOut(ostream, param_sd);
00464 ostream << "</param>";
00465 break;
00466 case LLSD::TypeArray:
00467 {
00468
00469 LLSD::array_iterator it = param_sd.beginArray();
00470 LLSD::array_iterator end = param_sd.endArray();
00471 for(; it != end; ++it)
00472 {
00473 ostream << "<param>";
00474 streamOut(ostream, *it);
00475 ostream << "</param>";
00476 }
00477 break;
00478 }
00479 default:
00480 ostream << "<param>";
00481 streamOut(ostream, param_sd);
00482 ostream << "</param>";
00483 break;
00484 }
00485
00486 stream << XMLRPC_REQUEST_FOOTER;
00487 return STATUS_DONE;
00488 }
00489
00493
00494
00495
00496 LLIOPipe::EStatus stream_out(std::ostream& ostr, XMLRPC_VALUE value)
00497 {
00498 XMLRPC_VALUE_TYPE_EASY type = XMLRPC_GetValueTypeEasy(value);
00499 LLIOPipe::EStatus status = LLIOPipe::STATUS_OK;
00500 switch(type)
00501 {
00502 case xmlrpc_type_base64:
00503 {
00504 S32 len = XMLRPC_GetValueStringLen(value);
00505 const char* buf = XMLRPC_GetValueBase64(value);
00506 ostr << " b(";
00507 if((len > 0) && buf)
00508 {
00509 ostr << len << ")\"";
00510 ostr.write(buf, len);
00511 ostr << "\"";
00512 }
00513 else
00514 {
00515 ostr << "0)\"\"";
00516 }
00517 break;
00518 }
00519 case xmlrpc_type_boolean:
00520
00521 ostr << " " << (XMLRPC_GetValueBoolean(value) ? "true" : "false");
00522 break;
00523 case xmlrpc_type_datetime:
00524 ostr << " d\"" << XMLRPC_GetValueDateTime_ISO8601(value) << "\"";
00525 break;
00526 case xmlrpc_type_double:
00527 ostr << " r" << XMLRPC_GetValueDouble(value);
00528
00529
00530 break;
00531 case xmlrpc_type_int:
00532 ostr << " i" << XMLRPC_GetValueInt(value);
00533
00534
00535 break;
00536 case xmlrpc_type_string:
00537
00538 ostr << " s(" << XMLRPC_GetValueStringLen(value) << ")'"
00539 << XMLRPC_GetValueString(value) << "'";
00540 break;
00541 case xmlrpc_type_array:
00542 case xmlrpc_type_mixed:
00543 {
00544
00545 ostr << " [";
00546 U32 needs_comma = 0;
00547 XMLRPC_VALUE current = XMLRPC_VectorRewind(value);
00548 while(current && (LLIOPipe::STATUS_OK == status))
00549 {
00550 if(needs_comma++) ostr << ",";
00551 status = stream_out(ostr, current);
00552 current = XMLRPC_VectorNext(value);
00553 }
00554 ostr << "]";
00555 break;
00556 }
00557 case xmlrpc_type_struct:
00558 {
00559
00560 ostr << " {";
00561 std::string name;
00562 U32 needs_comma = 0;
00563 XMLRPC_VALUE current = XMLRPC_VectorRewind(value);
00564 while(current && (LLIOPipe::STATUS_OK == status))
00565 {
00566 if(needs_comma++) ostr << ",";
00567 name.assign(XMLRPC_GetValueID(current));
00568 ostr << "'" << LLSDNotationFormatter::escapeString(name) << "':";
00569 status = stream_out(ostr, current);
00570 current = XMLRPC_VectorNext(value);
00571 }
00572 ostr << "}";
00573 break;
00574 }
00575 case xmlrpc_type_empty:
00576 case xmlrpc_type_none:
00577 default:
00578 status = LLIOPipe::STATUS_ERROR;
00579 llwarns << "Found an empty xmlrpc type.." << llendl;
00580
00581 break;
00582 };
00583 return status;
00584 }
00585
00586 LLFilterXMLRPCResponse2LLSD::LLFilterXMLRPCResponse2LLSD()
00587 {
00588 }
00589
00590 LLFilterXMLRPCResponse2LLSD::~LLFilterXMLRPCResponse2LLSD()
00591 {
00592 }
00593
00594 LLIOPipe::EStatus LLFilterXMLRPCResponse2LLSD::process_impl(
00595 const LLChannelDescriptors& channels,
00596 buffer_ptr_t& buffer,
00597 bool& eos,
00598 LLSD& context,
00599 LLPumpIO* pump)
00600 {
00601 PUMP_DEBUG;
00602 if(!eos) return STATUS_BREAK;
00603 if(!buffer) return STATUS_ERROR;
00604
00605 PUMP_DEBUG;
00606
00607
00608
00609 S32 bytes = buffer->countAfter(channels.in(), NULL);
00610 if(!bytes) return STATUS_ERROR;
00611 char* buf = new char[bytes + 1];
00612 buf[bytes] = '\0';
00613 buffer->readAfter(channels.in(), NULL, (U8*)buf, bytes);
00614
00615
00616
00617 PUMP_DEBUG;
00618 XMLRPC_REQUEST response = XMLRPC_REQUEST_FromXML(
00619 buf,
00620 bytes,
00621 NULL);
00622 if(!response)
00623 {
00624 llwarns << "XML -> SD Response unable to parse xml." << llendl;
00625 delete[] buf;
00626 return STATUS_ERROR;
00627 }
00628
00629 PUMP_DEBUG;
00630 LLBufferStream stream(channels, buffer.get());
00631 stream.precision(DEFAULT_PRECISION);
00632 if(XMLRPC_ResponseIsFault(response))
00633 {
00634 PUMP_DEBUG;
00635 stream << LLSDRPC_FAULT_HADER_1
00636 << XMLRPC_GetResponseFaultCode(response)
00637 << LLSDRPC_FAULT_HADER_2;
00638 const char* fault_str = XMLRPC_GetResponseFaultString(response);
00639 std::string fault_string;
00640 if(fault_str)
00641 {
00642 fault_string.assign(fault_str);
00643 }
00644 stream << "'" << LLSDNotationFormatter::escapeString(fault_string)
00645 << "'" <<LLSDRPC_FAULT_FOOTER;
00646 }
00647 else
00648 {
00649 PUMP_DEBUG;
00650 stream << LLSDRPC_RESPONSE_HEADER;
00651 XMLRPC_VALUE param = XMLRPC_RequestGetData(response);
00652 if(param)
00653 {
00654 stream_out(stream, param);
00655 }
00656 stream << LLSDRPC_RESPONSE_FOOTER;
00657 }
00658 PUMP_DEBUG;
00659 XMLRPC_RequestFree(response, 1);
00660 delete[] buf;
00661 PUMP_DEBUG;
00662 return STATUS_DONE;
00663 }
00664
00668 LLFilterXMLRPCRequest2LLSD::LLFilterXMLRPCRequest2LLSD()
00669 {
00670 }
00671
00672 LLFilterXMLRPCRequest2LLSD::~LLFilterXMLRPCRequest2LLSD()
00673 {
00674 }
00675
00676 LLIOPipe::EStatus LLFilterXMLRPCRequest2LLSD::process_impl(
00677 const LLChannelDescriptors& channels,
00678 buffer_ptr_t& buffer,
00679 bool& eos,
00680 LLSD& context,
00681 LLPumpIO* pump)
00682 {
00683 PUMP_DEBUG;
00684 if(!eos) return STATUS_BREAK;
00685 if(!buffer) return STATUS_ERROR;
00686
00687 PUMP_DEBUG;
00688
00689
00690
00691 S32 bytes = buffer->countAfter(channels.in(), NULL);
00692 if(!bytes) return STATUS_ERROR;
00693 char* buf = new char[bytes + 1];
00694 buf[bytes] = '\0';
00695 buffer->readAfter(channels.in(), NULL, (U8*)buf, bytes);
00696
00697
00698
00699 PUMP_DEBUG;
00700 XMLRPC_REQUEST request = XMLRPC_REQUEST_FromXML(
00701 buf,
00702 bytes,
00703 NULL);
00704 if(!request)
00705 {
00706 llwarns << "XML -> SD Request process parse error." << llendl;
00707 delete[] buf;
00708 return STATUS_ERROR;
00709 }
00710
00711 PUMP_DEBUG;
00712 LLBufferStream stream(channels, buffer.get());
00713 stream.precision(DEFAULT_PRECISION);
00714 const char* name = XMLRPC_RequestGetMethodName(request);
00715 stream << LLSDRPC_REQUEST_HEADER_1 << (name ? name : "")
00716 << LLSDRPC_REQUEST_HEADER_2;
00717 XMLRPC_VALUE param = XMLRPC_RequestGetData(request);
00718 if(param)
00719 {
00720 PUMP_DEBUG;
00721 S32 size = XMLRPC_VectorSize(param);
00722 if(size > 1)
00723 {
00724
00725
00726 stream << "[";
00727 }
00728 XMLRPC_VALUE current = XMLRPC_VectorRewind(param);
00729 bool needs_comma = false;
00730 while(current)
00731 {
00732 if(needs_comma)
00733 {
00734 stream << ",";
00735 }
00736 needs_comma = true;
00737 stream_out(stream, current);
00738 current = XMLRPC_VectorNext(param);
00739 }
00740 if(size > 1)
00741 {
00742
00743 stream << "]";
00744 }
00745 }
00746 stream << LLSDRPC_REQUEST_FOOTER;
00747 XMLRPC_RequestFree(request, 1);
00748 delete[] buf;
00749 PUMP_DEBUG;
00750 return STATUS_DONE;
00751 }
00752