1use minidom::Element;
2
3use error::Error;
4
5use ns;
6
7#[derive(Debug, Clone)]
8pub struct URI {
9 pub type_: String,
10 pub uri: String,
11}
12
13#[derive(Debug, Clone)]
14pub struct MediaElement {
15 pub width: Option<usize>,
16 pub height: Option<usize>,
17 pub uris: Vec<URI>,
18}
19
20pub fn parse_media_element(root: &Element) -> Result<MediaElement, Error> {
21 if !root.is("media", ns::MEDIA_ELEMENT) {
22 return Err(Error::ParseError("This is not a media element."));
23 }
24
25 let width = root.attr("width").and_then(|width| width.parse().ok());
26 let height = root.attr("height").and_then(|height| height.parse().ok());
27 let mut uris = vec!();
28 for uri in root.children() {
29 if uri.is("uri", ns::MEDIA_ELEMENT) {
30 let type_ = uri.attr("type").ok_or(Error::ParseError("Attribute type on uri is mandatory."))?;
31 let text = uri.text().trim().to_owned();
32 if text == "" {
33 return Err(Error::ParseError("URI missing in uri."));
34 }
35 uris.push(URI { type_: type_.to_owned(), uri: text });
36 } else {
37 return Err(Error::ParseError("Unknown child in media element."));
38 }
39 }
40 Ok(MediaElement { width: width, height: height, uris: uris })
41}
42
43#[cfg(test)]
44mod tests {
45 use minidom::Element;
46 use error::Error;
47 use media_element;
48 use data_forms;
49
50 #[test]
51 fn test_simple() {
52 let elem: Element = "<media xmlns='urn:xmpp:media-element'/>".parse().unwrap();
53 let media = media_element::parse_media_element(&elem).unwrap();
54 assert!(media.width.is_none());
55 assert!(media.height.is_none());
56 assert!(media.uris.is_empty());
57 }
58
59 #[test]
60 fn test_width_height() {
61 let elem: Element = "<media xmlns='urn:xmpp:media-element' width='32' height='32'/>".parse().unwrap();
62 let media = media_element::parse_media_element(&elem).unwrap();
63 assert_eq!(media.width.unwrap(), 32);
64 assert_eq!(media.height.unwrap(), 32);
65 }
66
67 #[test]
68 fn test_uri() {
69 let elem: Element = "<media xmlns='urn:xmpp:media-element'><uri type='text/html'>https://example.org/</uri></media>".parse().unwrap();
70 let media = media_element::parse_media_element(&elem).unwrap();
71 assert_eq!(media.uris.len(), 1);
72 assert_eq!(media.uris[0].type_, "text/html");
73 assert_eq!(media.uris[0].uri, "https://example.org/");
74 }
75
76 #[test]
77 fn test_invalid_width_height() {
78 let elem: Element = "<media xmlns='urn:xmpp:media-element' width=''/>".parse().unwrap();
79 let media = media_element::parse_media_element(&elem).unwrap();
80 assert!(media.width.is_none());
81
82 let elem: Element = "<media xmlns='urn:xmpp:media-element' width='coucou'/>".parse().unwrap();
83 let media = media_element::parse_media_element(&elem).unwrap();
84 assert!(media.width.is_none());
85
86 let elem: Element = "<media xmlns='urn:xmpp:media-element' height=''/>".parse().unwrap();
87 let media = media_element::parse_media_element(&elem).unwrap();
88 assert!(media.height.is_none());
89
90 let elem: Element = "<media xmlns='urn:xmpp:media-element' height='-10'/>".parse().unwrap();
91 let media = media_element::parse_media_element(&elem).unwrap();
92 assert!(media.height.is_none());
93 }
94
95 #[test]
96 fn test_unknown_child() {
97 let elem: Element = "<media xmlns='urn:xmpp:media-element'><coucou/></media>".parse().unwrap();
98 let error = media_element::parse_media_element(&elem).unwrap_err();
99 let message = match error {
100 Error::ParseError(string) => string,
101 _ => panic!(),
102 };
103 assert_eq!(message, "Unknown child in media element.");
104 }
105
106 #[test]
107 fn test_bad_uri() {
108 let elem: Element = "<media xmlns='urn:xmpp:media-element'><uri>https://example.org/</uri></media>".parse().unwrap();
109 let error = media_element::parse_media_element(&elem).unwrap_err();
110 let message = match error {
111 Error::ParseError(string) => string,
112 _ => panic!(),
113 };
114 assert_eq!(message, "Attribute type on uri is mandatory.");
115
116 let elem: Element = "<media xmlns='urn:xmpp:media-element'><uri type='text/html'/></media>".parse().unwrap();
117 let error = media_element::parse_media_element(&elem).unwrap_err();
118 let message = match error {
119 Error::ParseError(string) => string,
120 _ => panic!(),
121 };
122 assert_eq!(message, "URI missing in uri.");
123 }
124
125 #[test]
126 fn test_xep_ex1() {
127 let elem: Element = r#"
128<media xmlns='urn:xmpp:media-element'>
129 <uri type='audio/x-wav'>
130 http://victim.example.com/challenges/speech.wav?F3A6292C
131 </uri>
132 <uri type='audio/ogg; codecs=speex'>
133 cid:sha1+a15a505e360702b79c75a5f67773072ed392f52a@bob.xmpp.org
134 </uri>
135 <uri type='audio/mpeg'>
136 http://victim.example.com/challenges/speech.mp3?F3A6292C
137 </uri>
138</media>"#.parse().unwrap();
139 let media = media_element::parse_media_element(&elem).unwrap();
140 assert!(media.width.is_none());
141 assert!(media.height.is_none());
142 assert_eq!(media.uris.len(), 3);
143 assert_eq!(media.uris[0].type_, "audio/x-wav");
144 assert_eq!(media.uris[0].uri, "http://victim.example.com/challenges/speech.wav?F3A6292C");
145 assert_eq!(media.uris[1].type_, "audio/ogg; codecs=speex");
146 assert_eq!(media.uris[1].uri, "cid:sha1+a15a505e360702b79c75a5f67773072ed392f52a@bob.xmpp.org");
147 assert_eq!(media.uris[2].type_, "audio/mpeg");
148 assert_eq!(media.uris[2].uri, "http://victim.example.com/challenges/speech.mp3?F3A6292C");
149 }
150
151 #[test]
152 fn test_xep_ex2() {
153 let elem: Element = r#"
154<x xmlns='jabber:x:data' type='form'>
155 [ ... ]
156 <field var='ocr'>
157 <media xmlns='urn:xmpp:media-element'
158 height='80'
159 width='290'>
160 <uri type='image/jpeg'>
161 http://www.victim.com/challenges/ocr.jpeg?F3A6292C
162 </uri>
163 <uri type='image/jpeg'>
164 cid:sha1+f24030b8d91d233bac14777be5ab531ca3b9f102@bob.xmpp.org
165 </uri>
166 </media>
167 </field>
168 [ ... ]
169</x>"#.parse().unwrap();
170 let form = data_forms::parse_data_form(&elem).unwrap();
171 assert_eq!(form.fields.len(), 1);
172 assert_eq!(form.fields[0].var, "ocr");
173 assert_eq!(form.fields[0].media[0].width, Some(290));
174 assert_eq!(form.fields[0].media[0].height, Some(80));
175 assert_eq!(form.fields[0].media[0].uris[0].type_, "image/jpeg");
176 assert_eq!(form.fields[0].media[0].uris[0].uri, "http://www.victim.com/challenges/ocr.jpeg?F3A6292C");
177 assert_eq!(form.fields[0].media[0].uris[1].type_, "image/jpeg");
178 assert_eq!(form.fields[0].media[0].uris[1].uri, "cid:sha1+f24030b8d91d233bac14777be5ab531ca3b9f102@bob.xmpp.org");
179 }
180}