From 1faa79e461acfca16a36cb6efc4f78b5d9ae00f4 Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Tue, 11 Oct 2016 13:57:23 +0200 Subject: [PATCH] Add some documentation and tests to ::bits::parse. --- src/bits/parse.rs | 100 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 1 deletion(-) diff --git a/src/bits/parse.rs b/src/bits/parse.rs index 3fad9ceb..a79a5938 100644 --- a/src/bits/parse.rs +++ b/src/bits/parse.rs @@ -1,4 +1,13 @@ -//! Traits and implementations for parsing. +//! Parsing of DNS wire-format data. +//! +//! This module contains [`Parser`], the type wrapping the data of a DNS +//! message for parsing, as well as the error and result types for parsing. +//! You will only need to deal with parsing directly if you implement new +//! record data types. Otherwise, the [`Message`] type wraps everyhing up +//! in a nice, easy to use interface. +//! +//! [`Parser`]: struct.Parser.html +//! [`Message`]: ../message/struct.Message.html use std::error; use std::fmt; @@ -7,6 +16,24 @@ use byteorder::{BigEndian, ByteOrder}; //------------ Parser -------------------------------------------------------- +/// A type wrapping DNS message data for parsing. +/// +/// Because of name compression, a full message needs to be available for +/// parsing of DNS data. If you have received a message over the wire, you +/// can use it to create a parser via the [`new()`] function. +/// +/// The parser then allows you to successively parse one item after the other +/// out of the message via a few methods prefixed with `parse_`. Further +/// methods are available to retrieve some information about the parser +/// state, seek to a new position, or limit the amount of data the parser +/// allows to retrieve. +/// +/// Parsers are `Clone`, so you can keep around a copy of a parser for later +/// use. This is, for instance, done by [`ParsedDName`] in order to be able +/// to rummage around the message bytes to find all its labels. +/// +/// [`new()`]: #method.new +/// [`ParsedDName`]: ../name/struct.ParsedDName.html #[derive(Clone, Debug)] pub struct Parser<'a> { bytes: &'a [u8], @@ -15,6 +42,7 @@ pub struct Parser<'a> { } impl<'a> Parser<'a> { + /// Creates a new parser atop a bytes slice. pub fn new(bytes: &'a [u8]) -> Self { Parser{limit: bytes.len(), bytes: bytes, pos: 0} } @@ -122,6 +150,7 @@ impl<'a> Parser<'a> { } } + //------------ ParseError and ParseResult ----------------------------------- /// An error happening during parsing of wire-format DNS data. @@ -162,3 +191,72 @@ impl fmt::Display for ParseError { /// The result type for a `ParseError`. pub type ParseResult = Result; + +//============ Testing ====================================================== + +#[cfg(test)] +mod test { + use super::*; + + fn check(parser: &Parser, pos: usize, left: &[u8]) { + assert_eq!(parser.pos(), pos); + assert_eq!(parser.remaining(), left.len()); + assert_eq!(&parser.bytes()[pos..], left) + } + + #[test] + fn parse_bytes_ok() { + let mut parser = Parser::new(b"123456"); + check(&parser, 0, b"123456"); + assert_eq!(parser.parse_bytes(0).unwrap(), b""); + check(&parser, 0, b"123456"); + assert_eq!(parser.parse_bytes(4).unwrap(), b"1234"); + check(&parser, 4, b"56"); + assert_eq!(parser.parse_bytes(2).unwrap(), b"56"); + check(&parser, 6, b""); + assert_eq!(parser.parse_bytes(0).unwrap(), b""); + check(&parser, 6, b""); + } + + #[test] + fn parse_bytes_err() { + let mut parser = Parser::new(b"123456"); + check(&parser, 0, b"123456"); + assert_eq!(parser.parse_bytes(8), Err(ParseError::UnexpectedEnd)); + check(&parser, 0, b"123456"); + } + + #[test] + fn skip() { + let mut parser = Parser::new(b"123456"); + check(&parser, 0, b"123456"); + parser.skip(2).unwrap(); + check(&parser, 2, b"3456"); + assert_eq!(parser.skip(6), Err(ParseError::UnexpectedEnd)); + check(&parser, 2, b"3456"); + } + + #[test] + fn parse_u8() { + let mut parser = Parser::new(b"123"); + check(&parser, 0, b"123"); + assert_eq!(parser.parse_u8().unwrap(), b'1'); + check(&parser, 1, b"23"); + } + + #[test] + fn parse_u16() { + let mut parser = Parser::new(b"\x12\x3456"); + check(&parser, 0, b"\x12\x3456"); + assert_eq!(parser.parse_u16().unwrap(), 0x1234); + check(&parser, 2, b"56"); + } + + #[test] + fn parse_u32() { + let mut parser = Parser::new(b"\x12\x34\x56\x7890"); + check(&parser, 0, b"\x12\x34\x56\x7890"); + assert_eq!(parser.parse_u32().unwrap(), 0x12345678); + check(&parser, 4, b"90"); + } +}