1use std::{
5 fmt,
6 io::{self, Read},
7};
8
9use byteorder::{BigEndian, ReadBytesExt};
10use futures::{try_ready, Async, Future, Poll, Stream};
11use log::{debug, error};
12use num_traits::FromPrimitive;
13
14use crate::{ipp::*, IppAttribute, IppAttributeGroup, IppAttributes, IppHeader, IppReadExt, IppValue, PayloadKind};
15
16#[derive(Debug)]
18pub enum ParseError {
19 InvalidTag(u8),
20 InvalidVersion,
21 InvalidCollection,
22 Incomplete,
23 IOError(io::Error),
24}
25
26impl From<io::Error> for ParseError {
27 fn from(error: io::Error) -> Self {
28 match error.kind() {
29 io::ErrorKind::UnexpectedEof => ParseError::Incomplete,
30 _ => ParseError::IOError(error),
31 }
32 }
33}
34
35impl fmt::Display for ParseError {
36 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
37 match self {
38 ParseError::InvalidTag(tag) => write!(f, "Invalid tag: {}", tag),
39 ParseError::InvalidVersion => write!(f, "Invalid IPP protocol version"),
40 ParseError::InvalidCollection => write!(f, "Invalid IPP collection"),
41 ParseError::Incomplete => write!(f, "Incomplete IPP payload"),
42 ParseError::IOError(err) => write!(f, "{}", err.to_string()),
43 }
44 }
45}
46
47impl std::error::Error for ParseError {}
48
49fn list_or_value(mut list: Vec<IppValue>) -> IppValue {
51 if list.len() == 1 {
52 list.remove(0)
53 } else {
54 IppValue::ListOf(list)
55 }
56}
57
58pub struct IppParseResult {
60 pub header: IppHeader,
61 pub attributes: IppAttributes,
62 pub payload: Option<PayloadKind>,
63}
64
65impl IppParseResult {
66 fn new(header: IppHeader, attributes: IppAttributes) -> IppParseResult {
67 IppParseResult {
68 header,
69 attributes,
70 payload: None,
71 }
72 }
73}
74
75pub struct IppParser<'a> {
77 reader: &'a mut Read,
78 current_group: Option<IppAttributeGroup>,
79 last_name: Option<String>,
80 context: Vec<Vec<IppValue>>,
81 attributes: IppAttributes,
82}
83
84impl<'a> IppParser<'a> {
85 pub fn new(reader: &'a mut Read) -> IppParser<'a> {
87 IppParser {
88 reader,
89 current_group: None,
90 last_name: None,
91 context: vec![vec![]],
92 attributes: IppAttributes::new(),
93 }
94 }
95
96 fn add_last_attribute(&mut self) {
97 if let Some(ref last_name) = self.last_name {
98 if let Some(val_list) = self.context.pop() {
99 if let Some(ref mut group) = self.current_group {
100 group.attributes_mut().insert(
101 last_name.clone(),
102 IppAttribute::new(&last_name, list_or_value(val_list)),
103 );
104 }
105 }
106 self.context.push(vec![]);
107 }
108 }
109
110 fn parse_delimiter(&mut self, tag: u8) -> Result<DelimiterTag, ParseError> {
111 debug!("Delimiter tag: {:0x}", tag);
112
113 let tag = DelimiterTag::from_u8(tag).ok_or_else(|| ParseError::InvalidTag(tag))?;
114 if tag == DelimiterTag::EndOfAttributes {
115 self.add_last_attribute();
116 }
117
118 if let Some(group) = self.current_group.take() {
119 self.attributes.groups_mut().push(group);
120 }
121
122 self.current_group = Some(IppAttributeGroup::new(tag));
123
124 Ok(tag)
125 }
126
127 fn parse_value(&mut self, tag: u8) -> Result<(), ParseError> {
128 let namelen = self.reader.read_u16::<BigEndian>()?;
130 let name = self.reader.read_string(namelen as usize)?;
131 let value = IppValue::read(tag, &mut self.reader)?;
132
133 debug!("Value tag: {:0x}: {}: {}", tag, name, value);
134
135 if namelen > 0 {
136 self.add_last_attribute();
138 self.last_name = Some(name);
140 }
141 if tag == ValueTag::BegCollection as u8 {
142 debug!("Begin collection");
144 match value {
145 IppValue::Other { ref data, .. } if data.is_empty() => {}
146 _ => {
147 error!("Invalid begin collection attribute");
148 return Err(ParseError::InvalidCollection);
149 }
150 }
151 self.context.push(vec![]);
152 } else if tag == ValueTag::EndCollection as u8 {
153 debug!("End collection");
155 match value {
156 IppValue::Other { ref data, .. } if data.is_empty() => {}
157 _ => {
158 error!("Invalid end collection attribute");
159 return Err(ParseError::InvalidCollection);
160 }
161 }
162 if let Some(arr) = self.context.pop() {
163 if let Some(val_list) = self.context.last_mut() {
164 val_list.push(IppValue::Collection(arr));
165 }
166 }
167 } else if let Some(val_list) = self.context.last_mut() {
168 val_list.push(value);
170 }
171 Ok(())
172 }
173
174 pub fn parse(mut self) -> Result<IppParseResult, ParseError> {
176 let header = IppHeader::from_reader(self.reader)?;
177 debug!("IPP header: {:?}", header);
178
179 loop {
180 match self.reader.read_u8()? {
181 tag @ 0x01...0x05 => {
182 if self.parse_delimiter(tag)? == DelimiterTag::EndOfAttributes {
183 break;
184 }
185 }
186 tag @ 0x10...0x4a => self.parse_value(tag)?,
187 tag => {
188 return Err(ParseError::InvalidTag(tag));
189 }
190 }
191 }
192
193 Ok(IppParseResult::new(header, self.attributes))
194 }
195}
196
197enum AsyncParseState {
198 Headers(Vec<u8>),
199 Payload(IppParseResult),
200}
201
202pub struct AsyncIppParser<I, E> {
204 state: AsyncParseState,
205 stream: Box<dyn Stream<Item = I, Error = E> + Send>,
206}
207
208impl<I, E> Future for AsyncIppParser<I, E>
209where
210 I: AsRef<[u8]>,
211 ParseError: From<E>,
212{
213 type Item = IppParseResult;
214 type Error = ParseError;
215
216 fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
217 while let Some(item) = try_ready!(self.stream.poll()) {
218 match self.state {
219 AsyncParseState::Headers(ref mut buffer) => {
220 buffer.extend_from_slice(item.as_ref());
221 let length = buffer.len() as u64;
222
223 let mut reader = io::Cursor::new(buffer);
224 let parser = IppParser::new(&mut reader);
225
226 match parser.parse() {
227 Ok(mut result) => {
228 debug!("Parse ok, proceeding to payload state");
229 if reader.position() < length {
230 debug!("Adding residual payload from this chunk");
231 let mut temp = tempfile::NamedTempFile::new()?;
232 io::copy(&mut reader, &mut temp)?;
233 result.payload = Some(PayloadKind::ReceivedData(temp));
234 }
235 self.state = AsyncParseState::Payload(result);
236 }
237 Err(ParseError::Incomplete) => {
238 debug!("Incomplete request, awaiting for more data");
239 }
240 Err(e) => {
241 return Err(e);
242 }
243 }
244 }
245 AsyncParseState::Payload(ref mut result) => {
246 let mut reader = io::Cursor::new(&item);
247 match result.payload {
248 Some(PayloadKind::ReceivedData(ref mut file)) => {
249 debug!(
250 "Payload chunk received, appending to existing file: {}",
251 file.path().display()
252 );
253 io::copy(&mut reader, file)?;
254 }
255 None => {
256 let mut temp = tempfile::NamedTempFile::new()?;
257 debug!("Payload chunk received, creating new file: {}", temp.path().display());
258 io::copy(&mut reader, &mut temp)?;
259 result.payload = Some(PayloadKind::ReceivedData(temp));
260 }
261 _ => panic!("Should not happen"),
262 }
263 }
264 }
265 }
266
267 match self.state {
268 AsyncParseState::Headers(_) => Err(ParseError::Incomplete),
269 AsyncParseState::Payload(ref mut result) => {
270 debug!("Parsing finished, payload: {}", result.payload.is_some());
271 Ok(Async::Ready(IppParseResult {
272 header: result.header.clone(),
273 attributes: result.attributes.clone(),
274 payload: result.payload.take(),
275 }))
276 }
277 }
278 }
279}
280
281impl<I, E> From<Box<dyn Stream<Item = I, Error = E> + Send>> for AsyncIppParser<I, E> {
282 fn from(s: Box<dyn Stream<Item = I, Error = E> + Send>) -> AsyncIppParser<I, E> {
284 AsyncIppParser {
285 state: AsyncParseState::Headers(Vec::new()),
286 stream: s,
287 }
288 }
289}
290
291#[cfg(test)]
292mod tests {
293 use std::io::Cursor;
294
295 use super::*;
296
297 #[test]
298 fn test_parse_no_attributes() {
299 let data = &[1, 1, 0, 0, 0, 0, 0, 0, 3];
300 let result = IppParser::new(&mut Cursor::new(data)).parse();
301 assert!(result.is_ok());
302
303 let res = result.ok().unwrap();
304 assert!(res.attributes.groups().is_empty());
305 }
306
307 #[test]
308 fn test_parse_single_value() {
309 let data = &[
310 1, 1, 0, 0, 0, 0, 0, 0, 4, 0x21, 0x00, 0x04, b't', b'e', b's', b't', 0x00, 0x04, 0x12, 0x34, 0x56, 0x78, 3,
311 ];
312 let result = IppParser::new(&mut Cursor::new(data)).parse();
313 assert!(result.is_ok());
314
315 let res = result.ok().unwrap();
316 let attrs = res.attributes.groups_of(DelimiterTag::PrinterAttributes)[0].attributes();
317 let attr = attrs.get("test").unwrap();
318 assert_eq!(attr.value().as_integer(), Some(&0x12345678));
319 }
320
321 #[test]
322 fn test_parse_list() {
323 let data = &[
324 1, 1, 0, 0, 0, 0, 0, 0, 4, 0x21, 0x00, 0x04, b't', b'e', b's', b't', 0x00, 0x04, 0x12, 0x34, 0x56, 0x78,
325 0x21, 0x00, 0x00, 0x00, 0x04, 0x77, 0x65, 0x43, 0x21, 3,
326 ];
327 let result = IppParser::new(&mut Cursor::new(data)).parse();
328 assert!(result.is_ok());
329
330 let res = result.ok().unwrap();
331 let attrs = res.attributes.groups_of(DelimiterTag::PrinterAttributes)[0].attributes();
332 let attr = attrs.get("test").unwrap();
333 assert_eq!(
334 attr.value().as_listof(),
335 Some(&vec![IppValue::Integer(0x12345678), IppValue::Integer(0x77654321)])
336 );
337 }
338
339 #[test]
340 fn test_parse_collection() {
341 let data = vec![
342 1, 1, 0, 0, 0, 0, 0, 0, 4, 0x34, 0, 4, b'c', b'o', b'l', b'l', 0, 0, 0x21, 0, 0, 0, 4, 0x12, 0x34, 0x56,
343 0x78, 0x44, 0, 0, 0, 3, b'k', b'e', b'y', 0x37, 0, 0, 0, 0, 3,
344 ];
345 let result = IppParser::new(&mut Cursor::new(data)).parse();
346 assert!(result.is_ok());
347
348 let res = result.ok().unwrap();
349 let attrs = res.attributes.groups_of(DelimiterTag::PrinterAttributes)[0].attributes();
350 let attr = attrs.get("coll").unwrap();
351 assert_eq!(
352 attr.value().as_collection(),
353 Some(&vec![
354 IppValue::Integer(0x12345678),
355 IppValue::Keyword("key".to_owned())
356 ])
357 );
358 }
359
360 #[test]
361 fn test_async_parser_with_payload() {
362 let data = vec![
364 vec![1, 1, 0],
365 vec![0, 0, 0, 0, 0, 4],
366 vec![
367 0x21, 0x00, 0x04, b't', b'e', b's', b't', 0x00, 0x04, 0x12, 0x34, 0x56, 0x78, 3,
368 ],
369 vec![b'f'],
370 vec![b'o', b'o'],
371 ];
372
373 let source: Box<Stream<Item = Vec<u8>, Error = io::Error> + Send> =
374 Box::new(futures::stream::iter_ok::<_, io::Error>(data));
375
376 let parser = AsyncIppParser::from(source);
377
378 let mut runtime = tokio::runtime::Runtime::new().unwrap();
379 let result = runtime.block_on(parser);
380 assert!(result.is_ok());
381
382 let res = result.ok().unwrap();
383 let attrs = res.attributes.groups_of(DelimiterTag::PrinterAttributes)[0].attributes();
384 let attr = attrs.get("test").unwrap();
385 assert_eq!(attr.value().as_integer(), Some(&0x12345678));
386
387 match res.payload {
388 Some(PayloadKind::ReceivedData(f)) => {
389 let foo = std::fs::read_to_string(f.path()).unwrap();
390 assert_eq!(foo, "foo");
391 }
392 _ => panic!("Wrong payload!"),
393 }
394 }
395
396}