PageRenderTime 199ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/llmessage/llfiltersd2xmlrpc.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 777 lines | 690 code | 9 blank | 78 comment | 2 complexity | fb70d2815b9e772f10fbb3b6cc057b82 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llfiltersd2xmlrpc.cpp
  3. * @author Phoenix
  4. * @date 2005-04-26
  5. *
  6. * $LicenseInfo:firstyear=2005&license=viewerlgpl$
  7. * Second Life Viewer Source Code
  8. * Copyright (C) 2010, Linden Research, Inc.
  9. *
  10. * This library is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU Lesser General Public
  12. * License as published by the Free Software Foundation;
  13. * version 2.1 of the License only.
  14. *
  15. * This library is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  18. * Lesser General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Lesser General Public
  21. * License along with this library; if not, write to the Free Software
  22. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  23. *
  24. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  25. * $/LicenseInfo$
  26. */
  27. /**
  28. * xml rpc request:
  29. * <code>
  30. * <?xml version="1.0"?>
  31. * <methodCall><methodName>examples.getStateName</methodName>
  32. * <params><param><value><i4>41</i4></value></param></params>
  33. * </methodCall>
  34. * </code>
  35. *
  36. * xml rpc response:
  37. * <code>
  38. * <?xml version="1.0"?>
  39. * <methodResponse>
  40. * <params><param><value><string>South Dakota</string></value></param></params>
  41. * </methodResponse>
  42. * </code>
  43. *
  44. * xml rpc fault:
  45. * </code>
  46. * <?xml version="1.0"?>
  47. * <methodResponse>
  48. * <fault><value><struct>
  49. * <member><name>faultCode</name><value><int>4</int></value></member>
  50. * <member><name>faultString</name><value><string>...</string></value></member>
  51. * </struct></value></fault>
  52. * </methodResponse>
  53. * </code>
  54. *
  55. * llsd rpc request:
  56. * <code>
  57. * { 'method':'...', 'parameter':...]}
  58. * </code>
  59. *
  60. * llsd rpc response:
  61. * <code>
  62. * { 'response':... }
  63. * </code>
  64. *
  65. * llsd rpc fault:
  66. * <code>
  67. * { 'fault': {'code':i..., 'description':'...'} }
  68. * </code>
  69. *
  70. */
  71. #include "linden_common.h"
  72. #include "llfiltersd2xmlrpc.h"
  73. #include <sstream>
  74. #include <iterator>
  75. #include <xmlrpc-epi/xmlrpc.h>
  76. #include "apr_base64.h"
  77. #include "llbuffer.h"
  78. #include "llbufferstream.h"
  79. #include "llmemorystream.h"
  80. #include "llsd.h"
  81. #include "llsdserialize.h"
  82. #include "lluuid.h"
  83. // spammy mode
  84. //#define LL_SPEW_STREAM_OUT_DEBUGGING 1
  85. /**
  86. * String constants
  87. */
  88. static const char XML_HEADER[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
  89. static const char XMLRPC_REQUEST_HEADER_1[] = "<methodCall><methodName>";
  90. static const char XMLRPC_REQUEST_HEADER_2[] = "</methodName><params>";
  91. static const char XMLRPC_REQUEST_FOOTER[] = "</params></methodCall>";
  92. static const char XMLRPC_METHOD_RESPONSE_HEADER[] = "<methodResponse>";
  93. static const char XMLRPC_METHOD_RESPONSE_FOOTER[] = "</methodResponse>";
  94. static const char XMLRPC_RESPONSE_HEADER[] = "<params><param>";
  95. static const char XMLRPC_RESPONSE_FOOTER[] = "</param></params>";
  96. static const char XMLRPC_FAULT_1[] = "<fault><value><struct><member><name>faultCode</name><value><int>";
  97. static const char XMLRPC_FAULT_2[] = "</int></value></member><member><name>faultString</name><value><string>";
  98. static const char XMLRPC_FAULT_3[] = "</string></value></member></struct></value></fault>";
  99. static const char LLSDRPC_RESPONSE_HEADER[] = "{'response':";
  100. static const char LLSDRPC_RESPONSE_FOOTER[] = "}";
  101. const char LLSDRPC_REQUEST_HEADER_1[] = "{'method':'";
  102. const char LLSDRPC_REQUEST_HEADER_2[] = "', 'parameter': ";
  103. const char LLSDRPC_REQUEST_FOOTER[] = "}";
  104. static const char LLSDRPC_FAULT_HADER_1[] = "{ 'fault': {'code':i";
  105. static const char LLSDRPC_FAULT_HADER_2[] = ", 'description':";
  106. static const char LLSDRPC_FAULT_FOOTER[] = "} }";
  107. static const S32 DEFAULT_PRECISION = 20;
  108. /**
  109. * LLFilterSD2XMLRPC
  110. */
  111. LLFilterSD2XMLRPC::LLFilterSD2XMLRPC()
  112. {
  113. }
  114. LLFilterSD2XMLRPC::~LLFilterSD2XMLRPC()
  115. {
  116. }
  117. std::string xml_escape_string(const std::string& in)
  118. {
  119. std::ostringstream out;
  120. std::string::const_iterator it = in.begin();
  121. std::string::const_iterator end = in.end();
  122. for(; it != end; ++it)
  123. {
  124. switch((*it))
  125. {
  126. case '<':
  127. out << "&lt;";
  128. break;
  129. case '>':
  130. out << "&gt;";
  131. break;
  132. case '&':
  133. out << "&amp;";
  134. break;
  135. case '\'':
  136. out << "&apos;";
  137. break;
  138. case '"':
  139. out << "&quot;";
  140. break;
  141. default:
  142. out << (*it);
  143. break;
  144. }
  145. }
  146. return out.str();
  147. }
  148. void LLFilterSD2XMLRPC::streamOut(std::ostream& ostr, const LLSD& sd)
  149. {
  150. ostr << "<value>";
  151. switch(sd.type())
  152. {
  153. case LLSD::TypeMap:
  154. {
  155. #if LL_SPEW_STREAM_OUT_DEBUGGING
  156. llinfos << "streamOut(map) BEGIN" << llendl;
  157. #endif
  158. ostr << "<struct>";
  159. if(ostr.fail())
  160. {
  161. llinfos << "STREAM FAILURE writing struct" << llendl;
  162. }
  163. LLSD::map_const_iterator it = sd.beginMap();
  164. LLSD::map_const_iterator end = sd.endMap();
  165. for(; it != end; ++it)
  166. {
  167. ostr << "<member><name>" << xml_escape_string((*it).first)
  168. << "</name>";
  169. streamOut(ostr, (*it).second);
  170. if(ostr.fail())
  171. {
  172. llinfos << "STREAM FAILURE writing '" << (*it).first
  173. << "' with sd type " << (*it).second.type() << llendl;
  174. }
  175. ostr << "</member>";
  176. }
  177. ostr << "</struct>";
  178. #if LL_SPEW_STREAM_OUT_DEBUGGING
  179. llinfos << "streamOut(map) END" << llendl;
  180. #endif
  181. break;
  182. }
  183. case LLSD::TypeArray:
  184. {
  185. #if LL_SPEW_STREAM_OUT_DEBUGGING
  186. llinfos << "streamOut(array) BEGIN" << llendl;
  187. #endif
  188. ostr << "<array><data>";
  189. LLSD::array_const_iterator it = sd.beginArray();
  190. LLSD::array_const_iterator end = sd.endArray();
  191. for(; it != end; ++it)
  192. {
  193. streamOut(ostr, *it);
  194. if(ostr.fail())
  195. {
  196. llinfos << "STREAM FAILURE writing array element sd type "
  197. << (*it).type() << llendl;
  198. }
  199. }
  200. #if LL_SPEW_STREAM_OUT_DEBUGGING
  201. llinfos << "streamOut(array) END" << llendl;
  202. #endif
  203. ostr << "</data></array>";
  204. break;
  205. }
  206. case LLSD::TypeUndefined:
  207. // treat undefined as a bool with a false value.
  208. case LLSD::TypeBoolean:
  209. #if LL_SPEW_STREAM_OUT_DEBUGGING
  210. llinfos << "streamOut(bool)" << llendl;
  211. #endif
  212. ostr << "<boolean>" << (sd.asBoolean() ? "1" : "0") << "</boolean>";
  213. break;
  214. case LLSD::TypeInteger:
  215. #if LL_SPEW_STREAM_OUT_DEBUGGING
  216. llinfos << "streamOut(int)" << llendl;
  217. #endif
  218. ostr << "<i4>" << sd.asInteger() << "</i4>";
  219. break;
  220. case LLSD::TypeReal:
  221. #if LL_SPEW_STREAM_OUT_DEBUGGING
  222. llinfos << "streamOut(real)" << llendl;
  223. #endif
  224. ostr << "<double>" << sd.asReal() << "</double>";
  225. break;
  226. case LLSD::TypeString:
  227. #if LL_SPEW_STREAM_OUT_DEBUGGING
  228. llinfos << "streamOut(string)" << llendl;
  229. #endif
  230. ostr << "<string>" << xml_escape_string(sd.asString()) << "</string>";
  231. break;
  232. case LLSD::TypeUUID:
  233. #if LL_SPEW_STREAM_OUT_DEBUGGING
  234. llinfos << "streamOut(uuid)" << llendl;
  235. #endif
  236. // serialize it as a string
  237. ostr << "<string>" << sd.asString() << "</string>";
  238. break;
  239. case LLSD::TypeURI:
  240. {
  241. #if LL_SPEW_STREAM_OUT_DEBUGGING
  242. llinfos << "streamOut(uri)" << llendl;
  243. #endif
  244. // serialize it as a string
  245. ostr << "<string>" << xml_escape_string(sd.asString()) << "</string>";
  246. break;
  247. }
  248. case LLSD::TypeBinary:
  249. {
  250. #if LL_SPEW_STREAM_OUT_DEBUGGING
  251. llinfos << "streamOut(binary)" << llendl;
  252. #endif
  253. // this is pretty inefficient, but we'll deal with that
  254. // problem when it becomes one.
  255. ostr << "<base64>";
  256. LLSD::Binary buffer = sd.asBinary();
  257. if(!buffer.empty())
  258. {
  259. // *TODO: convert to LLBase64
  260. int b64_buffer_length = apr_base64_encode_len(buffer.size());
  261. char* b64_buffer = new char[b64_buffer_length];
  262. b64_buffer_length = apr_base64_encode_binary(
  263. b64_buffer,
  264. &buffer[0],
  265. buffer.size());
  266. ostr.write(b64_buffer, b64_buffer_length - 1);
  267. delete[] b64_buffer;
  268. }
  269. ostr << "</base64>";
  270. break;
  271. }
  272. case LLSD::TypeDate:
  273. #if LL_SPEW_STREAM_OUT_DEBUGGING
  274. llinfos << "streamOut(date)" << llendl;
  275. #endif
  276. // no need to escape this since it will be alpha-numeric.
  277. ostr << "<dateTime.iso8601>" << sd.asString() << "</dateTime.iso8601>";
  278. break;
  279. default:
  280. // unhandled type
  281. llwarns << "Unhandled structured data type: " << sd.type()
  282. << llendl;
  283. break;
  284. }
  285. ostr << "</value>";
  286. }
  287. /**
  288. * LLFilterSD2XMLRPCResponse
  289. */
  290. LLFilterSD2XMLRPCResponse::LLFilterSD2XMLRPCResponse()
  291. {
  292. }
  293. LLFilterSD2XMLRPCResponse::~LLFilterSD2XMLRPCResponse()
  294. {
  295. }
  296. static LLFastTimer::DeclareTimer FTM_PROCESS_SD2XMLRPC_RESPONSE("SD2XMLRPC Response");
  297. // virtual
  298. LLIOPipe::EStatus LLFilterSD2XMLRPCResponse::process_impl(
  299. const LLChannelDescriptors& channels,
  300. buffer_ptr_t& buffer,
  301. bool& eos,
  302. LLSD& context,
  303. LLPumpIO* pump)
  304. {
  305. LLFastTimer t(FTM_PROCESS_SD2XMLRPC_RESPONSE);
  306. PUMP_DEBUG;
  307. // This pipe does not work if it does not have everyting. This
  308. // could be addressed by making a stream parser for llsd which
  309. // handled partial information.
  310. if(!eos)
  311. {
  312. return STATUS_BREAK;
  313. }
  314. PUMP_DEBUG;
  315. // we have everyting in the buffer, so turn the structure data rpc
  316. // response into an xml rpc response.
  317. LLBufferStream stream(channels, buffer.get());
  318. stream << XML_HEADER << XMLRPC_METHOD_RESPONSE_HEADER;
  319. LLSD sd;
  320. LLSDSerialize::fromNotation(sd, stream, buffer->count(channels.in()));
  321. PUMP_DEBUG;
  322. LLIOPipe::EStatus rv = STATUS_ERROR;
  323. if(sd.has("response"))
  324. {
  325. PUMP_DEBUG;
  326. // it is a normal response. pack it up and ship it out.
  327. stream.precision(DEFAULT_PRECISION);
  328. stream << XMLRPC_RESPONSE_HEADER;
  329. streamOut(stream, sd["response"]);
  330. stream << XMLRPC_RESPONSE_FOOTER << XMLRPC_METHOD_RESPONSE_FOOTER;
  331. rv = STATUS_DONE;
  332. }
  333. else if(sd.has("fault"))
  334. {
  335. PUMP_DEBUG;
  336. // it is a fault.
  337. stream << XMLRPC_FAULT_1 << sd["fault"]["code"].asInteger()
  338. << XMLRPC_FAULT_2
  339. << xml_escape_string(sd["fault"]["description"].asString())
  340. << XMLRPC_FAULT_3 << XMLRPC_METHOD_RESPONSE_FOOTER;
  341. rv = STATUS_DONE;
  342. }
  343. else
  344. {
  345. llwarns << "Unable to determine the type of LLSD response." << llendl;
  346. }
  347. PUMP_DEBUG;
  348. return rv;
  349. }
  350. /**
  351. * LLFilterSD2XMLRPCRequest
  352. */
  353. LLFilterSD2XMLRPCRequest::LLFilterSD2XMLRPCRequest()
  354. {
  355. }
  356. LLFilterSD2XMLRPCRequest::LLFilterSD2XMLRPCRequest(const char* method)
  357. {
  358. if(method)
  359. {
  360. mMethod.assign(method);
  361. }
  362. }
  363. LLFilterSD2XMLRPCRequest::~LLFilterSD2XMLRPCRequest()
  364. {
  365. }
  366. static LLFastTimer::DeclareTimer FTM_PROCESS_SD2XMLRPC_REQUEST("S22XMLRPC Request");
  367. // virtual
  368. LLIOPipe::EStatus LLFilterSD2XMLRPCRequest::process_impl(
  369. const LLChannelDescriptors& channels,
  370. buffer_ptr_t& buffer,
  371. bool& eos,
  372. LLSD& context,
  373. LLPumpIO* pump)
  374. {
  375. LLFastTimer t(FTM_PROCESS_SD2XMLRPC_REQUEST);
  376. // This pipe does not work if it does not have everyting. This
  377. // could be addressed by making a stream parser for llsd which
  378. // handled partial information.
  379. PUMP_DEBUG;
  380. if(!eos)
  381. {
  382. llinfos << "!eos" << llendl;
  383. return STATUS_BREAK;
  384. }
  385. // See if we can parse it
  386. LLBufferStream stream(channels, buffer.get());
  387. LLSD sd;
  388. LLSDSerialize::fromNotation(sd, stream, buffer->count(channels.in()));
  389. if(stream.fail())
  390. {
  391. llinfos << "STREAM FAILURE reading structure data." << llendl;
  392. }
  393. PUMP_DEBUG;
  394. // We can get the method and parameters from either the member
  395. // function or passed in via the buffer. We prefer the buffer if
  396. // we found a parameter and a method, or fall back to using
  397. // mMethod and putting everyting in the buffer into the parameter.
  398. std::string method;
  399. LLSD param_sd;
  400. if(sd.has("method") && sd.has("parameter"))
  401. {
  402. method = sd["method"].asString();
  403. param_sd = sd["parameter"];
  404. }
  405. else
  406. {
  407. method = mMethod;
  408. param_sd = sd;
  409. }
  410. if(method.empty())
  411. {
  412. llwarns << "SD -> XML Request no method found." << llendl;
  413. return STATUS_ERROR;
  414. }
  415. PUMP_DEBUG;
  416. // We have a method, and some kind of parameter, so package it up
  417. // and send it out.
  418. LLBufferStream ostream(channels, buffer.get());
  419. ostream.precision(DEFAULT_PRECISION);
  420. if(ostream.fail())
  421. {
  422. llinfos << "STREAM FAILURE setting precision" << llendl;
  423. }
  424. ostream << XML_HEADER << XMLRPC_REQUEST_HEADER_1
  425. << xml_escape_string(method) << XMLRPC_REQUEST_HEADER_2;
  426. if(ostream.fail())
  427. {
  428. llinfos << "STREAM FAILURE writing method headers" << llendl;
  429. }
  430. switch(param_sd.type())
  431. {
  432. case LLSD::TypeMap:
  433. // If the params are a map, then we do not want to iterate
  434. // through them since the iterators returned will be map
  435. // ordered un-named values, which will lose the names, and
  436. // only stream the values, turning it into an array.
  437. ostream << "<param>";
  438. streamOut(ostream, param_sd);
  439. ostream << "</param>";
  440. break;
  441. case LLSD::TypeArray:
  442. {
  443. LLSD::array_iterator it = param_sd.beginArray();
  444. LLSD::array_iterator end = param_sd.endArray();
  445. for(; it != end; ++it)
  446. {
  447. ostream << "<param>";
  448. streamOut(ostream, *it);
  449. ostream << "</param>";
  450. }
  451. break;
  452. }
  453. default:
  454. ostream << "<param>";
  455. streamOut(ostream, param_sd);
  456. ostream << "</param>";
  457. break;
  458. }
  459. stream << XMLRPC_REQUEST_FOOTER;
  460. return STATUS_DONE;
  461. }
  462. /**
  463. * LLFilterXMLRPCResponse2LLSD
  464. */
  465. // this is a c function here since it's really an implementation
  466. // detail that requires a header file just get the definition of the
  467. // parameters.
  468. LLIOPipe::EStatus stream_out(std::ostream& ostr, XMLRPC_VALUE value)
  469. {
  470. XMLRPC_VALUE_TYPE_EASY type = XMLRPC_GetValueTypeEasy(value);
  471. LLIOPipe::EStatus status = LLIOPipe::STATUS_OK;
  472. switch(type)
  473. {
  474. case xmlrpc_type_base64:
  475. {
  476. S32 len = XMLRPC_GetValueStringLen(value);
  477. const char* buf = XMLRPC_GetValueBase64(value);
  478. ostr << " b(";
  479. if((len > 0) && buf)
  480. {
  481. ostr << len << ")\"";
  482. ostr.write(buf, len);
  483. ostr << "\"";
  484. }
  485. else
  486. {
  487. ostr << "0)\"\"";
  488. }
  489. break;
  490. }
  491. case xmlrpc_type_boolean:
  492. //lldebugs << "stream_out() bool" << llendl;
  493. ostr << " " << (XMLRPC_GetValueBoolean(value) ? "true" : "false");
  494. break;
  495. case xmlrpc_type_datetime:
  496. ostr << " d\"" << XMLRPC_GetValueDateTime_ISO8601(value) << "\"";
  497. break;
  498. case xmlrpc_type_double:
  499. ostr << " r" << XMLRPC_GetValueDouble(value);
  500. //lldebugs << "stream_out() double" << XMLRPC_GetValueDouble(value)
  501. // << llendl;
  502. break;
  503. case xmlrpc_type_int:
  504. ostr << " i" << XMLRPC_GetValueInt(value);
  505. //lldebugs << "stream_out() integer:" << XMLRPC_GetValueInt(value)
  506. // << llendl;
  507. break;
  508. case xmlrpc_type_string:
  509. //lldebugs << "stream_out() string: " << str << llendl;
  510. ostr << " s(" << XMLRPC_GetValueStringLen(value) << ")'"
  511. << XMLRPC_GetValueString(value) << "'";
  512. break;
  513. case xmlrpc_type_array: // vector
  514. case xmlrpc_type_mixed: // vector
  515. {
  516. //lldebugs << "stream_out() array" << llendl;
  517. ostr << " [";
  518. U32 needs_comma = 0;
  519. XMLRPC_VALUE current = XMLRPC_VectorRewind(value);
  520. while(current && (LLIOPipe::STATUS_OK == status))
  521. {
  522. if(needs_comma++) ostr << ",";
  523. status = stream_out(ostr, current);
  524. current = XMLRPC_VectorNext(value);
  525. }
  526. ostr << "]";
  527. break;
  528. }
  529. case xmlrpc_type_struct: // still vector
  530. {
  531. //lldebugs << "stream_out() struct" << llendl;
  532. ostr << " {";
  533. std::string name;
  534. U32 needs_comma = 0;
  535. XMLRPC_VALUE current = XMLRPC_VectorRewind(value);
  536. while(current && (LLIOPipe::STATUS_OK == status))
  537. {
  538. if(needs_comma++) ostr << ",";
  539. name.assign(XMLRPC_GetValueID(current));
  540. ostr << "'" << LLSDNotationFormatter::escapeString(name) << "':";
  541. status = stream_out(ostr, current);
  542. current = XMLRPC_VectorNext(value);
  543. }
  544. ostr << "}";
  545. break;
  546. }
  547. case xmlrpc_type_empty:
  548. case xmlrpc_type_none:
  549. default:
  550. status = LLIOPipe::STATUS_ERROR;
  551. llwarns << "Found an empty xmlrpc type.." << llendl;
  552. // not much we can do here...
  553. break;
  554. };
  555. return status;
  556. }
  557. LLFilterXMLRPCResponse2LLSD::LLFilterXMLRPCResponse2LLSD()
  558. {
  559. }
  560. LLFilterXMLRPCResponse2LLSD::~LLFilterXMLRPCResponse2LLSD()
  561. {
  562. }
  563. static LLFastTimer::DeclareTimer FTM_PROCESS_XMLRPC2LLSD_RESPONSE("XMLRPC2LLSD Response");
  564. LLIOPipe::EStatus LLFilterXMLRPCResponse2LLSD::process_impl(
  565. const LLChannelDescriptors& channels,
  566. buffer_ptr_t& buffer,
  567. bool& eos,
  568. LLSD& context,
  569. LLPumpIO* pump)
  570. {
  571. LLFastTimer t(FTM_PROCESS_XMLRPC2LLSD_RESPONSE);
  572. PUMP_DEBUG;
  573. if(!eos) return STATUS_BREAK;
  574. if(!buffer) return STATUS_ERROR;
  575. PUMP_DEBUG;
  576. // *FIX: This technique for reading data is far from optimal. We
  577. // need to have some kind of istream interface into the xml
  578. // parser...
  579. S32 bytes = buffer->countAfter(channels.in(), NULL);
  580. if(!bytes) return STATUS_ERROR;
  581. char* buf = new char[bytes + 1];
  582. buf[bytes] = '\0';
  583. buffer->readAfter(channels.in(), NULL, (U8*)buf, bytes);
  584. //lldebugs << "xmlrpc response: " << buf << llendl;
  585. PUMP_DEBUG;
  586. XMLRPC_REQUEST response = XMLRPC_REQUEST_FromXML(
  587. buf,
  588. bytes,
  589. NULL);
  590. if(!response)
  591. {
  592. llwarns << "XML -> SD Response unable to parse xml." << llendl;
  593. delete[] buf;
  594. return STATUS_ERROR;
  595. }
  596. PUMP_DEBUG;
  597. LLBufferStream stream(channels, buffer.get());
  598. stream.precision(DEFAULT_PRECISION);
  599. if(XMLRPC_ResponseIsFault(response))
  600. {
  601. PUMP_DEBUG;
  602. stream << LLSDRPC_FAULT_HADER_1
  603. << XMLRPC_GetResponseFaultCode(response)
  604. << LLSDRPC_FAULT_HADER_2;
  605. const char* fault_str = XMLRPC_GetResponseFaultString(response);
  606. std::string fault_string;
  607. if(fault_str)
  608. {
  609. fault_string.assign(fault_str);
  610. }
  611. stream << "'" << LLSDNotationFormatter::escapeString(fault_string)
  612. << "'" <<LLSDRPC_FAULT_FOOTER;
  613. }
  614. else
  615. {
  616. PUMP_DEBUG;
  617. stream << LLSDRPC_RESPONSE_HEADER;
  618. XMLRPC_VALUE param = XMLRPC_RequestGetData(response);
  619. if(param)
  620. {
  621. stream_out(stream, param);
  622. }
  623. stream << LLSDRPC_RESPONSE_FOOTER;
  624. }
  625. PUMP_DEBUG;
  626. XMLRPC_RequestFree(response, 1);
  627. delete[] buf;
  628. PUMP_DEBUG;
  629. return STATUS_DONE;
  630. }
  631. /**
  632. * LLFilterXMLRPCRequest2LLSD
  633. */
  634. LLFilterXMLRPCRequest2LLSD::LLFilterXMLRPCRequest2LLSD()
  635. {
  636. }
  637. LLFilterXMLRPCRequest2LLSD::~LLFilterXMLRPCRequest2LLSD()
  638. {
  639. }
  640. static LLFastTimer::DeclareTimer FTM_PROCESS_XMLRPC2LLSD_REQUEST("XMLRPC2LLSD Request");
  641. LLIOPipe::EStatus LLFilterXMLRPCRequest2LLSD::process_impl(
  642. const LLChannelDescriptors& channels,
  643. buffer_ptr_t& buffer,
  644. bool& eos,
  645. LLSD& context,
  646. LLPumpIO* pump)
  647. {
  648. LLFastTimer t(FTM_PROCESS_XMLRPC2LLSD_REQUEST);
  649. PUMP_DEBUG;
  650. if(!eos) return STATUS_BREAK;
  651. if(!buffer) return STATUS_ERROR;
  652. PUMP_DEBUG;
  653. // *FIX: This technique for reading data is far from optimal. We
  654. // need to have some kind of istream interface into the xml
  655. // parser...
  656. S32 bytes = buffer->countAfter(channels.in(), NULL);
  657. if(!bytes) return STATUS_ERROR;
  658. char* buf = new char[bytes + 1];
  659. buf[bytes] = '\0';
  660. buffer->readAfter(channels.in(), NULL, (U8*)buf, bytes);
  661. //lldebugs << "xmlrpc request: " << buf << llendl;
  662. // Check the value in the buffer. XMLRPC_REQUEST_FromXML will report a error code 4 if
  663. // values that are less than 0x20 are passed to it, except
  664. // 0x09: Horizontal tab; 0x0a: New Line; 0x0d: Carriage
  665. U8* cur_pBuf = (U8*)buf;
  666. U8 cur_char;
  667. for (S32 i=0; i<bytes; i++)
  668. {
  669. cur_char = *cur_pBuf;
  670. if ( cur_char < 0x20
  671. && 0x09 != cur_char
  672. && 0x0a != cur_char
  673. && 0x0d != cur_char )
  674. {
  675. *cur_pBuf = '?';
  676. }
  677. ++cur_pBuf;
  678. }
  679. PUMP_DEBUG;
  680. XMLRPC_REQUEST request = XMLRPC_REQUEST_FromXML(
  681. buf,
  682. bytes,
  683. NULL);
  684. if(!request)
  685. {
  686. llwarns << "XML -> SD Request process parse error." << llendl;
  687. delete[] buf;
  688. return STATUS_ERROR;
  689. }
  690. PUMP_DEBUG;
  691. LLBufferStream stream(channels, buffer.get());
  692. stream.precision(DEFAULT_PRECISION);
  693. const char* name = XMLRPC_RequestGetMethodName(request);
  694. stream << LLSDRPC_REQUEST_HEADER_1 << (name ? name : "")
  695. << LLSDRPC_REQUEST_HEADER_2;
  696. XMLRPC_VALUE param = XMLRPC_RequestGetData(request);
  697. if(param)
  698. {
  699. PUMP_DEBUG;
  700. S32 size = XMLRPC_VectorSize(param);
  701. if(size > 1)
  702. {
  703. // if there are multiple parameters, stuff the values into
  704. // an array so that the next step in the chain can read them.
  705. stream << "[";
  706. }
  707. XMLRPC_VALUE current = XMLRPC_VectorRewind(param);
  708. bool needs_comma = false;
  709. while(current)
  710. {
  711. if(needs_comma)
  712. {
  713. stream << ",";
  714. }
  715. needs_comma = true;
  716. stream_out(stream, current);
  717. current = XMLRPC_VectorNext(param);
  718. }
  719. if(size > 1)
  720. {
  721. // close the array
  722. stream << "]";
  723. }
  724. }
  725. stream << LLSDRPC_REQUEST_FOOTER;
  726. XMLRPC_RequestFree(request, 1);
  727. delete[] buf;
  728. PUMP_DEBUG;
  729. return STATUS_DONE;
  730. }