simple_xmlrpc/
lib.rs

1use std::result;
2
3use thiserror::Error as ThisError;
4
5/// Errors that can occur when trying to perform an XML-RPC request.
6///
7/// This can be a lower-level error (for example, the HTTP request failed), a problem with the
8/// server (maybe it's not implementing XML-RPC correctly), or just a failure to execute the
9/// operation.
10#[deprecated(since = "0.1.1", note = "please use `serde_xmlrpc::Error` instead")]
11#[derive(ThisError, Debug)]
12pub enum Error {
13    /// The response could not be parsed. This can happen when the server doesn't correctly
14    /// implement the XML-RPC spec.
15    #[error("parse error: {0}")]
16    ParseError(String),
17
18    /// The response could not be encoded.
19    #[error("encoding error: {0}")]
20    EncodingError(String),
21
22    /// The server returned a `<fault>` response, indicating that the execution of the call
23    /// encountered a problem (for example, an invalid (number of) arguments was passed).
24    #[error("server fault: {0}")]
25    Fault(#[from] Fault),
26}
27
28impl From<serde_xmlrpc::Error> for Error {
29    fn from(err: serde_xmlrpc::Error) -> Self {
30        match err {
31            serde_xmlrpc::Error::DecodingError(err) => Error::ParseError(err.to_string()),
32            serde_xmlrpc::Error::EncodingError(err) => Error::EncodingError(err.to_string()),
33            serde_xmlrpc::Error::Fault(fault) => Error::Fault(fault.into()),
34        }
35    }
36}
37
38#[deprecated(since = "0.1.1", note = "please use `serde_xmlrpc::Result` instead")]
39pub type Result<T> = result::Result<T, Error>;
40
41/// A `<fault>` response, indicating that a request failed.
42///
43/// The XML-RPC specification requires that a `<faultCode>` and `<faultString>` is returned in the
44/// `<fault>` case, further describing the error.
45#[deprecated(since = "0.1.2", note = "please use `serde_xmlrpc::Fault` instead")]
46#[derive(ThisError, Debug, PartialEq, Eq)]
47#[error("{fault_string} ({fault_code})")]
48pub struct Fault {
49    /// An application-specific error code.
50    pub fault_code: i32,
51    /// Human-readable error description.
52    pub fault_string: String,
53}
54
55impl From<serde_xmlrpc::Fault> for Fault {
56    fn from(fault: serde_xmlrpc::Fault) -> Self {
57        Fault {
58            fault_code: fault.fault_code,
59            fault_string: fault.fault_string,
60        }
61    }
62}
63
64#[deprecated(since = "0.1.2", note = "please use `serde_xmlrpc::Value` instead")]
65pub type Value = serde_xmlrpc::Value;
66
67#[deprecated(
68    since = "0.1.1",
69    note = "please use `serde_xmlrpc::response_from_str` instead"
70)]
71pub fn parse_response(data: &str) -> Result<Value> {
72    Ok(serde_xmlrpc::response_from_str(data)?)
73}
74
75#[deprecated(
76    since = "0.1.1",
77    note = "please use `serde_xmlrpc::value_from_str` instead"
78)]
79pub fn parse_value(data: &str) -> Result<Value> {
80    Ok(serde_xmlrpc::value_from_str(data)?)
81}
82
83#[deprecated(
84    since = "0.1.1",
85    note = "please use `serde_xmlrpc::request_to_string` instead"
86)]
87pub fn stringify_request(name: &str, args: &[Value]) -> Result<String> {
88    Ok(serde_xmlrpc::request_to_string(name, args.to_vec())?)
89}
90
91#[cfg(test)]
92mod tests {
93    use super::*;
94
95    #[test]
96    fn test_stringify_request() {
97        assert_eq!(
98            stringify_request("hello world", &[]).unwrap(),
99            r#"<?xml version="1.0" encoding="utf-8"?><methodCall><methodName>hello world</methodName><params></params></methodCall>"#.to_owned()
100        )
101    }
102
103    /// A 32-bit signed integer (`<i4>` or `<int>`).
104    #[test]
105    fn parse_int_values() {
106        assert_eq!(
107            parse_value("<value><i4>42</i4></value>").unwrap().as_i32(),
108            Some(42)
109        );
110
111        assert_eq!(
112            parse_value("<value><int>-42</int></value>")
113                .unwrap()
114                .as_i32(),
115            Some(-42)
116        );
117
118        assert_eq!(
119            parse_value("<value><int>2147483647</int></value>")
120                .unwrap()
121                .as_i32(),
122            Some(2147483647)
123        );
124    }
125
126    /// A 64-bit signed integer (`<i8>`).
127    #[test]
128    fn parse_long_values() {
129        assert_eq!(
130            parse_value("<value><i8>42</i8></value>").unwrap().as_i64(),
131            Some(42)
132        );
133
134        assert_eq!(
135            parse_value("<value><i8>9223372036854775807</i8></value>")
136                .unwrap()
137                .as_i64(),
138            Some(9223372036854775807)
139        );
140    }
141
142    /// A boolean value (`<boolean>`, 0 == `false`, 1 == `true`).
143    #[test]
144    fn parse_boolean_values() {
145        assert_eq!(
146            parse_value("<value><boolean>1</boolean></value>")
147                .unwrap()
148                .as_bool(),
149            Some(true)
150        );
151        assert_eq!(
152            parse_value("<value><boolean>0</boolean></value>")
153                .unwrap()
154                .as_bool(),
155            Some(false)
156        );
157    }
158
159    /// A string (`<string>`). Note that these can also appear as a raw
160    /// value tag as well.
161    #[test]
162    fn parse_string_values() {
163        assert_eq!(
164            parse_value("<value><string>hello</string></value>")
165                .unwrap()
166                .as_str(),
167            Some("hello")
168        );
169
170        assert_eq!(
171            parse_value("<value>world</value>").unwrap().as_str(),
172            Some("world")
173        );
174
175        assert_eq!(parse_value("<value />").unwrap().as_str(), Some(""));
176    }
177
178    /// A double-precision IEEE 754 floating point number (`<double>`).
179    #[test]
180    fn parse_double_values() {
181        assert_eq!(
182            parse_value("<value><double>1</double></value>")
183                .unwrap()
184                .as_f64(),
185            Some(1.0)
186        );
187        assert_eq!(
188            parse_value("<value><double>0</double></value>")
189                .unwrap()
190                .as_f64(),
191            Some(0.0)
192        );
193        assert_eq!(
194            parse_value("<value><double>42</double></value>")
195                .unwrap()
196                .as_f64(),
197            Some(42.0)
198        );
199        assert_eq!(
200            parse_value("<value><double>3.14</double></value>")
201                .unwrap()
202                .as_f64(),
203            Some(3.14)
204        );
205        assert_eq!(
206            parse_value("<value><double>-3.14</double></value>")
207                .unwrap()
208                .as_f64(),
209            Some(-3.14)
210        );
211    }
212
213    /// An ISO 8601 formatted date/time value (`<dateTime.iso8601>`).
214
215    /// Base64-encoded binary data (`<base64>`).
216    #[test]
217    fn parse_base64_values() {
218        assert_eq!(
219            parse_value("<value><base64>aGVsbG8gd29ybGQ=</base64></value>")
220                .unwrap()
221                .as_bytes(),
222            Some(&b"hello world"[..])
223        );
224    }
225
226    /// A mapping of named values (`<struct>`).
227
228    /// A list of arbitrary (heterogeneous) values (`<array>`).
229    #[test]
230    fn parse_array_values() {
231        assert_eq!(
232            parse_value(
233                "<value><array><data><value></value><value><nil /></value></data></array></value>"
234            )
235            .unwrap()
236            .as_array(),
237            Some(&[Value::String("".to_owned()), Value::Nil][..])
238        );
239    }
240
241    /// The empty (Unit) value (`<nil/>`).
242    #[test]
243    fn parse_nil_values() {
244        assert_eq!(parse_value("<value><nil /></value>").unwrap(), Value::Nil);
245    }
246
247    #[test]
248    fn parse_fault() {
249        let err = parse_response(
250            r#"<?xml version="1.0" encoding="utf-8"?>
251           <methodResponse>
252             <fault>
253               <value>
254                 <struct>
255                   <member>
256                     <name>faultCode</name>
257                     <value><int>4</int></value>
258                   </member>
259                   <member>
260                     <name>faultString</name>
261                     <value><string>Too many parameters.</string></value>
262                   </member>
263                 </struct>
264                </value>
265              </fault>
266            </methodResponse>"#,
267        )
268        .unwrap_err();
269
270        match err {
271            Error::Fault(f) => assert_eq!(
272                f,
273                Fault {
274                    fault_code: 4,
275                    fault_string: "Too many parameters.".into(),
276                }
277            ),
278            _ => {
279                assert!(false);
280            }
281        }
282    }
283}