1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
use {Value, Response};
use parser::parse_response;
use error::RequestError;
use utils::escape_xml;
use hyper::client::{Client, Body};
use hyper::header::{ContentType, UserAgent};
use std::io::{self, Write};
pub struct Request<'a> {
name: &'a str,
args: Vec<Value>,
}
impl<'a> Request<'a> {
pub fn new(name: &'a str) -> Self {
Request {
name: name,
args: Vec::new(),
}
}
pub fn arg<T: Into<Value>>(mut self, value: T) -> Self {
self.args.push(value.into());
Request {
name: self.name,
args: self.args,
}
}
pub fn call(&self, client: &Client, url: &str) -> RequestResult {
use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};
let mut body = Vec::new();
self.write_as_xml(&mut body)?;
let mut response = client.post(url)
.header(UserAgent("Rust xmlrpc".to_string()))
.header(ContentType(Mime(TopLevel::Text, SubLevel::Xml, vec![(Attr::Charset, Value::Utf8)])))
.body(Body::BufBody(&body, body.len()))
.send()?;
Ok(parse_response(&mut response)?)
}
pub fn write_as_xml<W: Write>(&self, fmt: &mut W) -> io::Result<()> {
write!(fmt, r#"<?xml version="1.0" encoding="utf-8"?>"#)?;
write!(fmt, r#"<methodCall>"#)?;
write!(fmt, r#" <methodName>{}</methodName>"#, escape_xml(&self.name))?;
write!(fmt, r#" <params>"#)?;
for value in &self.args {
write!(fmt, r#" <param>"#)?;
value.format(fmt)?;
write!(fmt, r#" </param>"#)?;
}
write!(fmt, r#" </params>"#)?;
write!(fmt, r#"</methodCall>"#)?;
Ok(())
}
}
pub type RequestResult = Result<Response, RequestError>;
#[cfg(test)]
mod tests {
use super::*;
use std::str;
#[test]
fn escapes_method_names() {
let mut output: Vec<u8> = Vec::new();
let req = Request::new("x<&x");
req.write_as_xml(&mut output).unwrap();
assert!(
str::from_utf8(&output)
.unwrap()
.contains("<methodName>x<&x</methodName>"));
}
}