xml_rpc/xmlfmt/
parse.rs
1use super::error::{Result, ResultExt};
2use super::{Call, Fault, Response, Value};
3use base64::{engine::general_purpose::STANDARD, Engine as _};
4use regex::Regex;
5use std;
6use std::collections::HashMap;
7
8fn wrap_in_string(content: String) -> String {
9 lazy_static! {
10 static ref RE1: Regex = Regex::new(r"<value\s*/>").unwrap();
11 static ref RE2: Regex = Regex::new(r"<value\s*>\s*<string\s*/>\s*</value\s*>").unwrap();
12 static ref RE3: Regex = Regex::new(r"<value\s*>(?P<rest>[^<>]*)</value\s*>").unwrap();
13 }
14 RE3.replace_all(
15 &RE2.replace_all(
16 &RE1.replace_all(&content, "<value><string></string></value>"),
17 "<value><string></string></value>",
18 ),
19 "<value><string>$rest</string></value>",
20 )
21 .into()
22}
23
24#[allow(dead_code)]
25pub fn xml<T: std::io::Read>(mut r: T) -> Result<Value> {
26 let mut content = String::new();
27 r.read_to_string(&mut content)
28 .chain_err(|| "Failed to read data source.")?;
29 let data: XmlValue = serde_xml_rs::from_str(&wrap_in_string(content))
30 .chain_err(|| "Failed to parse XML-RPC data.")?;
31 data.into()
32}
33
34pub fn call<T: std::io::Read>(mut r: T) -> Result<Call> {
35 let mut content = String::new();
36 r.read_to_string(&mut content)
37 .chain_err(|| "Failed to read data source.")?;
38 let data: XmlCall = serde_xml_rs::from_str(&wrap_in_string(content))
39 .chain_err(|| "Failed to parse XML-RPC call.")?;
40 data.into()
41}
42
43pub fn response<T: std::io::Read>(mut r: T) -> Result<Response> {
44 let mut content = String::new();
45 r.read_to_string(&mut content)
46 .chain_err(|| "Failed to read data source.")?;
47 let data: XmlResponse = serde_xml_rs::from_str(&wrap_in_string(content))
48 .chain_err(|| "Failed to parse XML-RPC response.")?;
49 data.into()
50}
51
52#[derive(Debug, PartialEq, Deserialize)]
53enum XmlValue {
54 #[serde(rename = "i4")]
55 I4(i32),
56 #[serde(rename = "int")]
57 Int(i32),
58 #[serde(rename = "boolean")]
59 Bool(i32),
60 #[serde(rename = "string")]
61 Str(String),
62 #[serde(rename = "double")]
63 Double(String),
64 #[serde(rename = "dateTime.iso8601")]
65 DateTime(String),
66 #[serde(rename = "base64")]
67 Base64(String),
68 #[serde(rename = "array")]
69 Array(XmlArray),
70 #[serde(rename = "struct")]
71 Struct(XmlStruct),
72}
73
74impl From<XmlValue> for Result<Value> {
75 fn from(val: XmlValue) -> Self {
76 Ok(match val {
77 XmlValue::I4(v) | XmlValue::Int(v) => Value::Int(v),
78 XmlValue::Bool(v) => Value::Bool(v != 0),
79 XmlValue::Str(v) => Value::String(v),
80 XmlValue::Double(v) => Value::Double(v.parse().chain_err(|| "Failed to parse double")?),
81 XmlValue::DateTime(v) => Value::DateTime(v),
82 XmlValue::Base64(v) => Value::Base64(
83 STANDARD
84 .decode(v.as_bytes())
85 .chain_err(|| "Failed to parse base64")?,
86 ),
87 XmlValue::Array(v) => {
88 let items: Result<Vec<Value>> = v.into();
89 Value::Array(items?)
90 }
91 XmlValue::Struct(v) => {
92 let items: Result<HashMap<String, Value>> = v.into();
93 Value::Struct(items?)
94 }
95 })
96 }
97}
98
99#[derive(Debug, PartialEq, Deserialize)]
100#[serde(rename = "methodCall")]
101struct XmlCall {
102 #[serde(rename = "methodName")]
103 pub name: String,
104 pub params: XmlParams,
105}
106
107impl From<XmlCall> for Result<Call> {
108 fn from(val: XmlCall) -> Self {
109 let params: Result<Vec<Value>> = val.params.into();
110 Ok(Call {
111 name: val.name,
112 params: params?,
113 })
114 }
115}
116
117#[derive(Debug, PartialEq, Deserialize)]
118enum XmlResponseResult {
119 #[serde(rename = "params")]
120 Success(XmlParams),
121 #[serde(rename = "fault")]
122 Failure { value: XmlValue },
123}
124
125impl From<XmlResponseResult> for Result<Response> {
126 fn from(val: XmlResponseResult) -> Self {
127 match val {
128 XmlResponseResult::Success(params) => {
129 let params: Result<Vec<Value>> = params.into();
130 Ok(Ok(params?))
131 }
132 XmlResponseResult::Failure { value: v } => {
133 use serde::Deserialize;
134
135 let val: Result<Value> = v.into();
136
137 Ok(Err(
138 Fault::deserialize(val?).chain_err(|| "Failed to decode fault structure")?
139 ))
140 }
141 }
142 }
143}
144
145#[derive(Debug, PartialEq, Deserialize)]
146enum XmlResponse {
147 #[serde(rename = "methodResponse")]
148 Response(XmlResponseResult),
149}
150
151impl From<XmlResponse> for Result<Response> {
152 fn from(val: XmlResponse) -> Self {
153 match val {
154 XmlResponse::Response(v) => v.into(),
155 }
156 }
157}
158
159#[derive(Debug, PartialEq, Deserialize)]
160struct XmlParams {
161 #[serde(rename = "param", default)]
162 pub params: Vec<XmlParamData>,
163}
164
165impl From<XmlParams> for Result<Vec<Value>> {
166 fn from(val: XmlParams) -> Self {
167 val.params
168 .into_iter()
169 .map(Into::<Result<Value>>::into)
170 .collect()
171 }
172}
173
174#[derive(Debug, PartialEq, Deserialize)]
175struct XmlParamData {
176 pub value: XmlValue,
177}
178
179impl From<XmlParamData> for Result<Value> {
180 fn from(val: XmlParamData) -> Self {
181 val.value.into()
182 }
183}
184
185#[derive(Debug, PartialEq, Deserialize)]
186struct XmlArray {
187 #[serde(rename = "data")]
188 pub data: XmlArrayData,
189}
190
191impl From<XmlArray> for Result<Vec<Value>> {
192 fn from(val: XmlArray) -> Self {
193 val.data.into()
194 }
195}
196
197#[derive(Debug, PartialEq, Deserialize)]
198struct XmlArrayData {
199 #[serde(default)]
200 pub value: Vec<XmlValue>,
201}
202
203impl From<XmlArrayData> for Result<Vec<Value>> {
204 fn from(val: XmlArrayData) -> Self {
205 val.value
206 .into_iter()
207 .map(Into::<Result<Value>>::into)
208 .collect()
209 }
210}
211
212#[derive(Debug, PartialEq, Deserialize)]
213struct XmlStruct {
214 #[serde(rename = "member", default)]
215 pub members: Vec<XmlStructItem>,
216}
217
218impl From<XmlStruct> for Result<HashMap<String, Value>> {
219 fn from(val: XmlStruct) -> Self {
220 val.members
221 .into_iter()
222 .map(Into::<Result<(String, Value)>>::into)
223 .collect()
224 }
225}
226
227#[derive(Debug, PartialEq, Deserialize)]
228struct XmlStructItem {
229 pub name: String,
230 pub value: XmlValue,
231}
232
233impl From<XmlStructItem> for Result<(String, Value)> {
234 fn from(val: XmlStructItem) -> Self {
235 let value: Result<Value> = val.value.into();
236 Ok((val.name, value?))
237 }
238}