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