serde_xmlrpc/
lib.rs

1//! This library provides a basic API for serializing / deserializng xmlrpc.
2//! Combine with your transport or server of choice for an easy and quick xmlrpc experience.
3
4use quick_xml::{events::Event, name::QName, Reader, Writer};
5use serde::Deserialize;
6use serde_transcode::transcode;
7
8mod error;
9mod util;
10mod value;
11
12use util::{ReaderExt, ValueDeserializer, ValueSerializer, WriterExt};
13
14pub use error::{Error, Fault, Result};
15pub use value::{to_value, Value};
16
17/// Parses the body of an xmlrpc http request and attempts to convert it to the desired type.
18/// ```
19/// let val: String = serde_xmlrpc::response_from_str(
20/// r#"<?xml version="1.0" encoding="utf-8"?>
21/// <methodResponse>
22///  <params>
23///    <param><value><string>hello world</string></value></param>
24///  </params>
25/// </methodResponse>"#).unwrap();
26///
27/// assert_eq!(val, "hello world".to_string());
28/// ```
29pub fn response_from_str<'a, T>(input: &'a str) -> Result<T>
30where
31    T: serde::de::Deserialize<'a>,
32{
33    let mut reader = Reader::from_str(input);
34    reader.expand_empty_elements(true);
35    reader.trim_text(true);
36
37    // Check the first event. This will determine if we're loading a Fault or a
38    // Value.
39    loop {
40        match reader.read_event().map_err(error::DecodingError::from)? {
41            Event::Decl(_) => continue,
42            Event::Start(e) if e.name() == QName(b"methodResponse") => {
43                break;
44            }
45            e => return Err(error::DecodingError::UnexpectedEvent(format!("{:?}", e)).into()),
46        };
47    }
48
49    match reader.read_event().map_err(error::DecodingError::from)? {
50        Event::Start(e) if e.name() == QName(b"params") => {
51            reader.expect_tag(QName(b"param"))?;
52            reader.expect_tag(QName(b"value"))?;
53            let deserializer = ValueDeserializer::new(&mut reader)?;
54            let ret = T::deserialize(deserializer)?;
55            reader
56                .read_to_end(QName(b"param"))
57                .map_err(error::DecodingError::from)?;
58            reader
59                .read_to_end(e.name())
60                .map_err(error::DecodingError::from)?;
61            Ok(ret)
62        }
63        Event::Start(e) if e.name() == QName(b"fault") => {
64            // The inner portion of a fault is just a Value tag, so we
65            // deserialize it from a value.
66            reader.expect_tag(QName(b"value"))?;
67            let deserializer = ValueDeserializer::new(&mut reader)?;
68            let fault: Fault = Fault::deserialize(deserializer)?;
69
70            // Pull the reader back out so we can verify the end tag.
71            //let mut reader = deserializer.into_inner();
72
73            reader
74                .read_to_end(e.name())
75                .map_err(error::DecodingError::from)?;
76
77            Err(fault.into())
78        }
79        e => Err(error::DecodingError::UnexpectedEvent(format!("{:?}", e)).into()),
80    }
81}
82
83/// Attempt to serialize a xmlrpc response from a list of values.
84/// Each item in the list will be represented as a separate "param" in xmlrpc parlance.
85/// ```
86/// use serde_xmlrpc::{response_to_string,Value};
87/// let body = response_to_string(vec![Value::Int(42), Value::String("data".to_string())].into_iter()).unwrap();
88/// assert_eq!(body,
89/// r#"<?xml version="1.0" encoding="utf-8"?><methodResponse><params><param><value><int>42</int></value></param><param><value><string>data</string></value></param></params></methodResponse>"#
90/// );
91/// ```
92pub fn response_to_string(params: impl Iterator<Item = Value>) -> Result<String> {
93    let mut writer = Writer::new(Vec::new());
94    writer.write_decl()?;
95
96    writer.write_start_tag("methodResponse")?;
97    writer.write_start_tag("params")?;
98    for value in params {
99        writer.write_start_tag("param")?;
100
101        let deserializer = value::Deserializer::from_value(value);
102        let serializer = ValueSerializer::new(&mut writer);
103        transcode(deserializer, serializer)?;
104
105        writer.write_end_tag("param")?;
106    }
107    writer.write_end_tag("params")?;
108    writer.write_end_tag("methodResponse")?;
109    Ok(String::from_utf8(writer.into_inner()).map_err(error::EncodingError::from)?)
110}
111
112/// Expects an input string which is a valid xmlrpc request body, and parses out the method name and parameters from it.
113/// This function would typically be used by a server to parse incoming requests.
114///   * Returns a tuple of (method name, Arguments) if successful
115/// This does not parse the types of the arguments, as typically the server needs to resolve
116/// the method name before it can know the expected types.
117pub fn request_from_str(request: &str) -> Result<(String, Vec<Value>)> {
118    let mut reader = Reader::from_str(request);
119    reader.expand_empty_elements(true);
120    reader.trim_text(true);
121
122    // Search for methodCall start
123    loop {
124        match reader.read_event().map_err(error::DecodingError::from)? {
125            Event::Decl(_) => continue,
126            Event::Start(e) if e.name() == QName(b"methodCall") => {
127                break;
128            }
129            e => return Err(error::DecodingError::UnexpectedEvent(format!("{:?}", e)).into()),
130        };
131    }
132
133    // This code currently assumes that the <methodName> will always precede <params>
134    // in the xmlrpc request, I'm not certain that this is actually enforced by the
135    // specification, but could find not counter example where it wasn't true... -Carter
136
137    let method_name = match reader.read_event().map_err(error::DecodingError::from)? {
138        Event::Start(e) if e.name() == QName(b"methodName") => reader
139            .read_text(e.name())
140            .map_err(error::DecodingError::from)?,
141        e => return Err(error::DecodingError::UnexpectedEvent(format!("{:?}", e)).into()),
142    };
143
144    match reader.read_event().map_err(error::DecodingError::from)? {
145        Event::Start(e) if e.name() == QName(b"params") => {
146            let mut params = Vec::new();
147
148            let params = loop {
149                break match reader.read_event().map_err(error::DecodingError::from)? {
150                    // Read each parameter into a Value
151                    Event::Start(e) if e.name() == QName(b"param") => {
152                        reader.expect_tag(QName(b"value"))?;
153                        let deserializer = ValueDeserializer::new(&mut reader)?;
154                        let serializer = value::Serializer::new();
155                        let x = transcode(deserializer, serializer)?;
156                        params.push(x);
157
158                        reader
159                            .read_to_end(e.name())
160                            .map_err(error::DecodingError::from)?;
161
162                        continue;
163                    }
164
165                    // Once we see the relevant params end tag, we know we have all the params.
166                    Event::End(e) if e.name() == QName(b"params") => params,
167                    e => {
168                        return Err(error::DecodingError::UnexpectedEvent(format!("{:?}", e)).into())
169                    }
170                };
171            };
172
173            // We can skip reading to the end of the params tag because if we're
174            // here, we've already hit the end tag.
175
176            Ok((method_name.into_owned(), params))
177        }
178        e => Err(error::DecodingError::UnexpectedEvent(format!("{:?}", e)).into()),
179    }
180}
181
182/// Takes in the name of a method call and a list of parameters and attempts to convert them to a String
183/// which would be a valid body for an xmlrpc request.
184///
185/// ```
186/// let body = serde_xmlrpc::request_to_string("myMethod", vec![1.into(), "param2".into()]);
187/// ```
188pub fn request_to_string(name: &str, args: Vec<Value>) -> Result<String> {
189    let mut writer = Writer::new(Vec::new());
190
191    writer.write_decl()?;
192
193    writer.write_start_tag("methodCall")?;
194    writer.write_tag("methodName", name)?;
195
196    writer.write_start_tag("params")?;
197    for value in args {
198        writer.write_start_tag("param")?;
199
200        let deserializer = value::Deserializer::from_value(value);
201        let serializer = ValueSerializer::new(&mut writer);
202        transcode(deserializer, serializer)?;
203
204        writer.write_end_tag("param")?;
205    }
206    writer.write_end_tag("params")?;
207    writer.write_end_tag("methodCall")?;
208
209    Ok(String::from_utf8(writer.into_inner()).map_err(error::EncodingError::from)?)
210}
211
212/// Attempts to parse an individual value out of a str.
213/// ```
214/// let x = serde_xmlrpc::value_from_str("<value><int>42</int></value>").unwrap().as_i32();
215/// assert_eq!(x, Some(42));
216/// ```
217pub fn value_from_str(input: &str) -> Result<Value> {
218    let mut reader = Reader::from_str(input);
219    reader.expand_empty_elements(true);
220    reader.trim_text(true);
221
222    reader.expect_tag(QName(b"value"))?;
223    let deserializer = ValueDeserializer::new(&mut reader)?;
224    let serializer = value::Serializer::new();
225    transcode(deserializer, serializer)
226}
227
228/// Attempts to convert any data type which can be represented as an xmlrpc value into a String.
229/// ```
230/// let a = serde_xmlrpc::value_to_string(42);
231/// let b = serde_xmlrpc::value_to_string("Text");
232/// let c = serde_xmlrpc::value_to_string(false);
233/// ```
234pub fn value_to_string<I>(val: I) -> Result<String>
235where
236    I: Into<Value>,
237{
238    let d = value::Deserializer::from_value(val.into());
239    let mut writer = Writer::new(Vec::new());
240    let s = ValueSerializer::new(&mut writer);
241    transcode(d, s)?;
242    Ok(String::from_utf8(writer.into_inner()).map_err(error::EncodingError::from)?)
243}
244
245/// Attempts to convert a Vec of values to any data type which can be deserialized.
246/// This is typically used with [request_from_str] to implement server behavior:
247/// ```
248/// let val = r#"<?xml version=\"1.0\"?>
249///   <methodCall>
250///     <methodName>requestTopic</methodName>
251///     <params>
252///       <param><value>/rosout</value></param>
253///       <param><value><int>42</int></value></param>
254///     </params>
255///   </methodCall>"#;
256/// // Parse the request
257/// let (method, vals) = serde_xmlrpc::request_from_str(val).unwrap();
258/// // Now that we know what method is being called we can typecast our args
259/// let (a, b): (String, i32) = serde_xmlrpc::from_values(vals).unwrap();
260/// ```
261pub fn from_values<T: serde::de::DeserializeOwned>(values: Vec<Value>) -> Result<T> {
262    // Wrap input vec into our value type so it is compatible with our deserializer
263    // Kinda a cheap hack, but I like returning Vec<Value> for the args to a function
264    // instead of a Value which is itself an array...
265    let val = Value::Array(values);
266    from_value(val)
267}
268
269/// Attempts to deserialize the Value into the given type, equivalent API of
270/// [serde_json::from_value](https://docs.rs/serde_json/latest/serde_json/fn.from_value.html).
271/// ```
272/// use serde_xmlrpc::{from_value, Value};
273/// let val = Value::Array(vec![Value::Int(3), Value::String("Test".to_string())]);
274/// let (x, y): (i32, String) = from_value(val).unwrap();
275/// ```
276pub fn from_value<T: serde::de::DeserializeOwned>(value: Value) -> Result<T> {
277    let d = value::Deserializer::from_value(value);
278    T::deserialize(d)
279}
280
281#[cfg(test)]
282mod tests {
283    use super::*;
284
285    #[test]
286    fn test_stringify_request() {
287        assert_eq!(
288            request_to_string("hello world", vec![]).unwrap(),
289            r#"<?xml version="1.0" encoding="utf-8"?><methodCall><methodName>hello world</methodName><params></params></methodCall>"#.to_owned()
290        )
291    }
292
293    /// A 32-bit signed integer (`<i4>` or `<int>`).
294    #[test]
295    fn parse_int_values() {
296        assert_eq!(
297            value_from_str("<value><int>42</int></value>")
298                .unwrap()
299                .as_i32(),
300            Some(42)
301        );
302
303        assert_eq!(
304            value_from_str("<value><int>-42</int></value>")
305                .unwrap()
306                .as_i32(),
307            Some(-42)
308        );
309
310        assert_eq!(
311            value_from_str("<value><int>2147483647</int></value>")
312                .unwrap()
313                .as_i32(),
314            Some(2147483647)
315        );
316    }
317
318    /// A 64-bit signed integer (`<i8>`).
319    #[test]
320    fn parse_long_values() {
321        assert_eq!(
322            value_from_str("<value><int>42</int></value>")
323                .unwrap()
324                .as_i64(),
325            Some(42)
326        );
327
328        assert_eq!(
329            value_from_str("<value><int>9223372036854775807</int></value>")
330                .unwrap()
331                .as_i64(),
332            Some(9223372036854775807)
333        );
334    }
335
336    /// A boolean value (`<boolean>`, 0 == `false`, 1 == `true`).
337    #[test]
338    fn parse_boolean_values() {
339        assert_eq!(
340            value_from_str("<value><boolean>1</boolean></value>")
341                .unwrap()
342                .as_bool(),
343            Some(true)
344        );
345        assert_eq!(
346            value_from_str("<value><boolean>0</boolean></value>")
347                .unwrap()
348                .as_bool(),
349            Some(false)
350        );
351    }
352
353    /// A string (`<string>`). Note that these can also appear as a raw
354    /// value tag as well.
355    #[test]
356    fn parse_string_values() {
357        assert_eq!(
358            value_from_str("<value><string>hello</string></value>")
359                .unwrap()
360                .as_str(),
361            Some("hello")
362        );
363
364        assert_eq!(
365            value_from_str("<value>world</value>").unwrap().as_str(),
366            Some("world")
367        );
368
369        assert_eq!(value_from_str("<value />").unwrap().as_str(), Some(""));
370    }
371
372    /// A double-precision IEEE 754 floating point number (`<double>`).
373    #[test]
374    fn parse_double_values() {
375        assert_eq!(
376            value_from_str("<value><double>1</double></value>")
377                .unwrap()
378                .as_f64(),
379            Some(1.0)
380        );
381        assert_eq!(
382            value_from_str("<value><double>0</double></value>")
383                .unwrap()
384                .as_f64(),
385            Some(0.0)
386        );
387        assert_eq!(
388            value_from_str("<value><double>42</double></value>")
389                .unwrap()
390                .as_f64(),
391            Some(42.0)
392        );
393        assert_eq!(
394            value_from_str("<value><double>3.14</double></value>")
395                .unwrap()
396                .as_f64(),
397            Some(3.14)
398        );
399        assert_eq!(
400            value_from_str("<value><double>-3.14</double></value>")
401                .unwrap()
402                .as_f64(),
403            Some(-3.14)
404        );
405    }
406
407    /// An ISO 8601 formatted date/time value (`<dateTime.iso8601>`).
408
409    /// Base64-encoded binary data (`<base64>`).
410    #[test]
411    fn parse_base64_values() {
412        assert_eq!(
413            value_from_str("<value><base64>aGVsbG8gd29ybGQ=</base64></value>")
414                .unwrap()
415                .as_bytes(),
416            Some(&b"hello world"[..])
417        );
418    }
419
420    /// A mapping of named values (`<struct>`).
421
422    /// A list of arbitrary (heterogeneous) values (`<array>`).
423    #[test]
424    fn parse_array_values() {
425        assert_eq!(
426            value_from_str(
427                "<value><array><data><value></value><value><nil /></value></data></array></value>"
428            )
429            .unwrap()
430            .as_array(),
431            Some(&[Value::String("".to_owned()), Value::Nil][..])
432        );
433    }
434
435    /// The empty (Unit) value (`<nil/>`).
436    #[test]
437    fn parse_nil_values() {
438        assert_eq!(
439            value_from_str("<value><nil /></value>").unwrap(),
440            Value::Nil
441        );
442    }
443
444    #[test]
445    fn parse_fault() {
446        let err = response_from_str::<String>(
447            r#"<?xml version="1.0" encoding="utf-8"?>
448           <methodResponse>
449             <fault>
450               <value>
451                 <struct>
452                   <member>
453                     <name>faultCode</name>
454                     <value><int>4</int></value>
455                   </member>
456                   <member>
457                     <name>faultString</name>
458                     <value><string>Too many parameters.</string></value>
459                   </member>
460                 </struct>
461                </value>
462              </fault>
463            </methodResponse>"#,
464        )
465        .unwrap_err();
466
467        match err {
468            error::Error::Fault(f) => assert_eq!(
469                f,
470                error::Fault {
471                    fault_code: 4,
472                    fault_string: "Too many parameters.".into(),
473                }
474            ),
475            _ => {
476                println!("{:?}", err);
477                assert!(false);
478            }
479        }
480    }
481
482    #[test]
483    fn parse_value() {
484        let val: String = response_from_str(
485            r#"<?xml version="1.0" encoding="utf-8"?>
486            <methodResponse>
487              <params>
488                <param><value><string>hello world</string></value></param>
489              </params>
490            </methodResponse>"#,
491        )
492        .unwrap();
493
494        assert_eq!(val, "hello world".to_string());
495    }
496
497    #[test]
498    fn test_parse_request_multiple_params() {
499        let val = r#"<?xml version=\"1.0\"?>
500          <methodCall>
501            <methodName>requestTopic</methodName>
502            <params>
503              <param><value>/rosout</value></param>
504              <param><value><int>42</int></value></param>
505              <param><value><array><data><value><array><data><value>TCPROS</value></data></array></value></data></array></value></param>
506            </params>
507          </methodCall>"#;
508
509        let (method, vals) = request_from_str(val).unwrap();
510        assert_eq!(&method, "requestTopic");
511
512        // This is a little redundant with test_from_values, but is easiest way
513        // to confirm parsing was perfect
514        let (a, b, c): (String, i32, Vec<Vec<String>>) = from_values(vals).unwrap();
515
516        assert_eq!(a, "/rosout");
517        assert_eq!(b, 42);
518        assert_eq!(c, vec![vec!["TCPROS".to_string()]]);
519    }
520
521    #[test]
522    fn test_response_to_value() {
523        // Ensure Value implementes serde::Deserialize. This allows reading
524        // responses into a Value rather than a specific type.
525        let val: Value = response_from_str(
526            r#"<?xml version="1.0" encoding="utf-8"?>
527            <methodResponse>
528              <params>
529                <param><value><string>hello world</string></value></param>
530              </params>
531            </methodResponse>"#,
532        )
533        .unwrap();
534
535        assert_eq!(val, Value::String("hello world".to_string()));
536    }
537
538    #[test]
539    fn test_from_values() {
540        let vals = vec![
541            Value::Int(32),
542            Value::Double(1.0),
543            Value::String("hello".to_string()),
544        ];
545
546        let (a, b, c): (i32, f64, String) = from_values(vals).unwrap();
547        assert_eq!(a, 32);
548        assert_eq!(b, 1.0);
549        assert_eq!(c, "hello");
550    }
551}