From: Richard Whitehouse Date: Mon, 22 Oct 2018 13:00:37 +0000 (-0400) Subject: Move chartype into a separate module X-Git-Url: https://git.richardwhiuk.com/?a=commitdiff_plain;h=76933c6d1a7d0116acb72f065b4a85b165a01ff2;p=rust-sip.git Move chartype into a separate module --- diff --git a/src/codec.rs b/src/codec.rs deleted file mode 100644 index b1d298c..0000000 --- a/src/codec.rs +++ /dev/null @@ -1,391 +0,0 @@ -use bytes::BytesMut; -use nom; -use std; -use std::io; -use tokio_io::codec::{Decoder, Encoder}; - -use parser::header; -use parser::top_line; -use types::{Header, Method, RequestLine, StatusLine, TopLine}; - -const SPACE: u8 = b' '; -const TAB: u8 = b'\t'; -const LF: u8 = b'\n'; -const CR: u8 = b'\r'; - -impl Header { - fn parse(line: UnparsedLine) -> Option<(Header, UnparsedLine)> { - match header(line.as_bytes()) { - nom::IResult::Done(_, h) => Some((h, line.clone())), - result => { - warn!("Failed to parse header: {:?} - {:?}", line, result); - None - } - } - } -} - -#[derive(Clone, Debug)] -struct UnparsedLine { - value: BytesMut, -} - -impl UnparsedLine { - fn new(value: BytesMut) -> UnparsedLine { - UnparsedLine { value: value } - } - - fn add(&mut self, value: &BytesMut) { - self.value.extend_from_slice(value); - } - - fn as_bytes(&self) -> &[u8] { - &self.value - } -} - -pub struct SipCodec { - message: Option, - headers: Vec, - top_line: Option, - latest_header: Option, -} - -impl SipCodec { - pub fn new() -> SipCodec { - SipCodec { - message: None, - headers: Vec::new(), - top_line: None, - latest_header: None, - } - } - - fn parse_message(&mut self, buf: &mut BytesMut) -> io::Result> { - loop { - trace!("Gathering headers from {:?}", std::str::from_utf8(&buf)); - - let mut done = false; - let mut total = 0; - - { - let mut search: Box> = Box::new(buf.iter()); - - while !done { - trace!("Gathering CRLF"); - - if let Some(cr) = search.position(|&b| b == CR) { - trace!("Found CR at {}", cr); - - total += cr; - - let next = search.next(); - - trace!("Got {:?} after CR", next); - - if let Some(&LF) = next { - done = true; - } - } else { - return Ok(None); - } - } - } - - // We've got a line terminating in \r\n. - let line = buf.split_to(total + 2); - - trace!("Using line: {:?}", std::str::from_utf8(&line)); - - match ( - &mut self.top_line, - chartype(line.first()), - &mut self.latest_header, - ) { - // Ignore empty top lines - (&mut None, CharType::Line, _) => { - trace!("Ignoring empty top line"); - } - - // Top line beginnning with whitespace - ignore - (&mut None, CharType::Whitespace, _) => { - trace!( - "Got top line beginning with whitespace - ignore: {:?}", - line - ); - } - - // Top line with no headers! Discard. - (top_line @ &mut None, CharType::Other, _) => { - trace!("Got new top line of request: {:?}", line); - - top_line.get_or_insert(UnparsedLine::new(line)); - } - - // Top line with no headers! Discard. - (top_line @ &mut Some(_), CharType::Line, &mut None) => { - warn!("Got request with no headers - discarding"); - top_line.take(); - } - - // Whitespace wrapped req line - (&mut Some(ref mut top_line), CharType::Whitespace, &mut None) => { - top_line.add(&line) - } - - // Whitespace wrapped header - (&mut Some(_), CharType::Whitespace, &mut Some(ref mut latest_header)) => { - latest_header.add(&line) - } - - // First header - (&mut Some(_), CharType::Other, latest_header @ &mut None) => { - latest_header.get_or_insert(UnparsedLine::new(line)); - } - - // New header - (&mut Some(_), CharType::Other, latest_header @ &mut Some(_)) => { - self.headers.push(latest_header.take().unwrap()); - latest_header.get_or_insert(UnparsedLine::new(line)); - } - - // End of headers - (top_line @ &mut Some(_), CharType::Line, old_header @ &mut Some(_)) => { - self.headers.push(old_header.take().unwrap()); - - trace!("Got end of headers"); - - if let Ok(new_message) = - PartialMessage::new(top_line.take().unwrap(), &mut self.headers) - { - debug!("Got partial message: {:?}", new_message); - - self.headers.clear(); - - let length = new_message.body_length(); - - if length == 0 { - if let Some(message) = Message::new(new_message) { - debug!("Got message without body: {:?}", message); - - return Ok(Some(message)); - } else { - debug!("Failed to parse message with no body!"); - } - } else if length > buf.len() { - self.message.get_or_insert(new_message); - return Ok(None); - } else { - let body = buf.split_to(length); - if let Some(message) = Message::new_with_body(new_message, body) { - debug!("Got message with body: {:?}", message); - - return Ok(Some(message)); - } else { - warn!("Failed to parse message with body!"); - } - } - } else { - warn!("Failed to parse partial message!"); - - // Message failed to parse - top_line.take(); - self.headers.clear(); - } - } - } - } - } -} - -#[derive(Debug)] -struct PartialMessage { - headers: Vec<(Header, UnparsedLine)>, - top_line: UnparsedLine, -} - -impl PartialMessage { - fn new( - top_line: UnparsedLine, - headers: &mut Vec, - ) -> Result { - Ok(PartialMessage { - top_line: top_line, - headers: headers - .drain(..) - .filter_map(|line| Header::parse(line)) - .collect(), - }) - } - - fn body_length(&self) -> usize { - let body_length = 0; - - body_length - } -} - -#[derive(Debug)] -pub enum Message { - Request(Request), - Response(Response), -} - -#[derive(Debug)] -pub struct Response { - status_line: (StatusLine, UnparsedLine), - headers: Vec<(Header, UnparsedLine)>, - body: Option, -} - -impl Response { - fn as_bytes(&self) -> &[u8] { - return self.status_line.1.as_bytes(); - } -} - -#[derive(Debug)] -pub struct Request { - request_line: (RequestLine, UnparsedLine), - headers: Vec<(Header, UnparsedLine)>, - body: Option, -} - -impl Request { - fn as_bytes(&self) -> &[u8] { - return self.request_line.1.as_bytes(); - } - - pub fn method(&self) -> &Method { - &self.request_line.0.method - } -} - -impl Message { - fn new(message: PartialMessage) -> Option { - Message::parse(message, None) - } - - fn parse(message: PartialMessage, body: Option) -> Option { - match top_line(message.top_line.as_bytes()) { - nom::IResult::Done(_, TopLine::RequestLine(r)) => Some(Message::Request(Request { - headers: message.headers, - request_line: (r, message.top_line.clone()), - body: body, - })), - nom::IResult::Done(_, TopLine::StatusLine(s)) => Some(Message::Response(Response { - headers: message.headers, - status_line: (s, message.top_line.clone()), - body: body, - })), - result => { - warn!("Failed to parse top line: {:?}", result); - None - } - } - } - - fn new_with_body(message: PartialMessage, body: BytesMut) -> Option { - Message::parse(message, Some(body)) - } - - fn as_bytes<'a>(&'a self) -> &'a [u8] { - match self { - &Message::Request(ref r) => r.as_bytes(), - &Message::Response(ref r) => r.as_bytes(), - } - } -} - -impl Decoder for SipCodec { - type Item = Message; - type Error = io::Error; - - fn decode(&mut self, buf: &mut BytesMut) -> io::Result> { - if let Some(_) = self.message { - trace!("Gathering body"); - - let length = self.message.iter().map(|m| m.body_length()).next().unwrap(); - - if length > buf.len() { - return Ok(None); - } else if let Some(message) = - Message::new_with_body(self.message.take().unwrap(), buf.split_to(length)) - { - return Ok(Some(message)); - } else { - warn!("Failed to parse message with no body!"); - } - } - - self.parse_message(buf) - } -} - -impl Encoder for SipCodec { - type Item = Message; - type Error = io::Error; - - fn encode(&mut self, msg: Message, buf: &mut BytesMut) -> io::Result<()> { - buf.extend(msg.as_bytes()); - Ok(()) - } -} - -#[derive(PartialEq, Debug)] -enum CharType { - Line, - Whitespace, - Other, -} - -fn chartype(char: Option<&u8>) -> CharType { - match char { - None | Some(&LF) | Some(&CR) => CharType::Line, - Some(&SPACE) | Some(&TAB) => CharType::Whitespace, - Some(_) => CharType::Other, - } -} - -#[cfg(test)] -mod tests { - - use super::*; - - #[test] - fn test_chartype_none() { - assert_eq!(chartype(None), CharType::Line); - } - - #[test] - fn test_chartype_cr() { - assert_eq!(chartype(Some(&LF)), CharType::Line); - } - - #[test] - fn test_chartype_lf() { - assert_eq!(chartype(Some(&CR)), CharType::Line); - } - - #[test] - fn test_chartype_space() { - assert_eq!(chartype(Some(&SPACE)), CharType::Whitespace); - } - - #[test] - fn test_chartype_tab() { - assert_eq!(chartype(Some(&TAB)), CharType::Whitespace); - } - - #[test] - fn test_chartype_alpha() { - const A: u8 = b'a'; - assert_eq!(chartype(Some(&A)), CharType::Other); - } - - #[test] - fn test_chartype_number() { - const ONE: u8 = b'1'; - assert_eq!(chartype(Some(&ONE)), CharType::Other); - } -} diff --git a/src/codec/chartype.rs b/src/codec/chartype.rs new file mode 100644 index 0000000..61953f8 --- /dev/null +++ b/src/codec/chartype.rs @@ -0,0 +1,61 @@ +const SPACE: u8 = b' '; +const TAB: u8 = b'\t'; +pub const LF: u8 = b'\n'; +pub const CR: u8 = b'\r'; + +#[derive(PartialEq, Debug)] +pub enum CharType { + Line, + Whitespace, + Other, +} + +pub fn chartype(char: Option<&u8>) -> CharType { + match char { + None | Some(&LF) | Some(&CR) => CharType::Line, + Some(&SPACE) | Some(&TAB) => CharType::Whitespace, + Some(_) => CharType::Other, + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_chartype_none() { + assert_eq!(chartype(None), CharType::Line); + } + + #[test] + fn test_chartype_cr() { + assert_eq!(chartype(Some(&LF)), CharType::Line); + } + + #[test] + fn test_chartype_lf() { + assert_eq!(chartype(Some(&CR)), CharType::Line); + } + + #[test] + fn test_chartype_space() { + assert_eq!(chartype(Some(&SPACE)), CharType::Whitespace); + } + + #[test] + fn test_chartype_tab() { + assert_eq!(chartype(Some(&TAB)), CharType::Whitespace); + } + + #[test] + fn test_chartype_alpha() { + const A: u8 = b'a'; + assert_eq!(chartype(Some(&A)), CharType::Other); + } + + #[test] + fn test_chartype_number() { + const ONE: u8 = b'1'; + assert_eq!(chartype(Some(&ONE)), CharType::Other); + } +} diff --git a/src/codec/mod.rs b/src/codec/mod.rs new file mode 100644 index 0000000..63804bb --- /dev/null +++ b/src/codec/mod.rs @@ -0,0 +1,331 @@ +use bytes::BytesMut; +use nom; +use std; +use std::io; +use tokio_io::codec::{Decoder, Encoder}; + +mod chartype; + +use self::chartype::{chartype, CharType, CR, LF}; +use parser::header; +use parser::top_line; +use types::{Header, Method, RequestLine, StatusLine, TopLine}; + +impl Header { + fn parse(line: UnparsedLine) -> Option<(Header, UnparsedLine)> { + match header(line.as_bytes()) { + nom::IResult::Done(_, h) => Some((h, line.clone())), + result => { + warn!("Failed to parse header: {:?} - {:?}", line, result); + None + } + } + } +} + +#[derive(Clone, Debug)] +struct UnparsedLine { + value: BytesMut, +} + +impl UnparsedLine { + fn new(value: BytesMut) -> UnparsedLine { + UnparsedLine { value: value } + } + + fn add(&mut self, value: &BytesMut) { + self.value.extend_from_slice(value); + } + + fn as_bytes(&self) -> &[u8] { + &self.value + } +} + +pub struct SipCodec { + message: Option, + headers: Vec, + top_line: Option, + latest_header: Option, +} + +impl SipCodec { + pub fn new() -> SipCodec { + SipCodec { + message: None, + headers: Vec::new(), + top_line: None, + latest_header: None, + } + } + + fn parse_message(&mut self, buf: &mut BytesMut) -> io::Result> { + loop { + trace!("Gathering headers from {:?}", std::str::from_utf8(&buf)); + + let mut done = false; + let mut total = 0; + + { + let mut search: Box> = Box::new(buf.iter()); + + while !done { + trace!("Gathering CRLF"); + + if let Some(cr) = search.position(|&b| b == CR) { + trace!("Found CR at {}", cr); + + total += cr; + + let next = search.next(); + + trace!("Got {:?} after CR", next); + + if let Some(&LF) = next { + done = true; + } + } else { + return Ok(None); + } + } + } + + // We've got a line terminating in \r\n. + let line = buf.split_to(total + 2); + + trace!("Using line: {:?}", std::str::from_utf8(&line)); + + match ( + &mut self.top_line, + chartype(line.first()), + &mut self.latest_header, + ) { + // Ignore empty top lines + (&mut None, CharType::Line, _) => { + trace!("Ignoring empty top line"); + } + + // Top line beginnning with whitespace - ignore + (&mut None, CharType::Whitespace, _) => { + trace!( + "Got top line beginning with whitespace - ignore: {:?}", + line + ); + } + + // Top line with no headers! Discard. + (top_line @ &mut None, CharType::Other, _) => { + trace!("Got new top line of request: {:?}", line); + + top_line.get_or_insert(UnparsedLine::new(line)); + } + + // Top line with no headers! Discard. + (top_line @ &mut Some(_), CharType::Line, &mut None) => { + warn!("Got request with no headers - discarding"); + top_line.take(); + } + + // Whitespace wrapped req line + (&mut Some(ref mut top_line), CharType::Whitespace, &mut None) => { + top_line.add(&line) + } + + // Whitespace wrapped header + (&mut Some(_), CharType::Whitespace, &mut Some(ref mut latest_header)) => { + latest_header.add(&line) + } + + // First header + (&mut Some(_), CharType::Other, latest_header @ &mut None) => { + latest_header.get_or_insert(UnparsedLine::new(line)); + } + + // New header + (&mut Some(_), CharType::Other, latest_header @ &mut Some(_)) => { + self.headers.push(latest_header.take().unwrap()); + latest_header.get_or_insert(UnparsedLine::new(line)); + } + + // End of headers + (top_line @ &mut Some(_), CharType::Line, old_header @ &mut Some(_)) => { + self.headers.push(old_header.take().unwrap()); + + trace!("Got end of headers"); + + if let Ok(new_message) = + PartialMessage::new(top_line.take().unwrap(), &mut self.headers) + { + debug!("Got partial message: {:?}", new_message); + + self.headers.clear(); + + let length = new_message.body_length(); + + if length == 0 { + if let Some(message) = Message::new(new_message) { + debug!("Got message without body: {:?}", message); + + return Ok(Some(message)); + } else { + debug!("Failed to parse message with no body!"); + } + } else if length > buf.len() { + self.message.get_or_insert(new_message); + return Ok(None); + } else { + let body = buf.split_to(length); + if let Some(message) = Message::new_with_body(new_message, body) { + debug!("Got message with body: {:?}", message); + + return Ok(Some(message)); + } else { + warn!("Failed to parse message with body!"); + } + } + } else { + warn!("Failed to parse partial message!"); + + // Message failed to parse + top_line.take(); + self.headers.clear(); + } + } + } + } + } +} + +#[derive(Debug)] +struct PartialMessage { + headers: Vec<(Header, UnparsedLine)>, + top_line: UnparsedLine, +} + +impl PartialMessage { + fn new( + top_line: UnparsedLine, + headers: &mut Vec, + ) -> Result { + Ok(PartialMessage { + top_line: top_line, + headers: headers + .drain(..) + .filter_map(|line| Header::parse(line)) + .collect(), + }) + } + + fn body_length(&self) -> usize { + let body_length = 0; + + body_length + } +} + +#[derive(Debug)] +pub enum Message { + Request(Request), + Response(Response), +} + +#[derive(Debug)] +pub struct Response { + status_line: (StatusLine, UnparsedLine), + headers: Vec<(Header, UnparsedLine)>, + body: Option, +} + +impl Response { + fn as_bytes(&self) -> &[u8] { + return self.status_line.1.as_bytes(); + } +} + +#[derive(Debug)] +pub struct Request { + request_line: (RequestLine, UnparsedLine), + headers: Vec<(Header, UnparsedLine)>, + body: Option, +} + +impl Request { + fn as_bytes(&self) -> &[u8] { + return self.request_line.1.as_bytes(); + } + + pub fn method(&self) -> &Method { + &self.request_line.0.method + } +} + +impl Message { + fn new(message: PartialMessage) -> Option { + Message::parse(message, None) + } + + fn parse(message: PartialMessage, body: Option) -> Option { + match top_line(message.top_line.as_bytes()) { + nom::IResult::Done(_, TopLine::RequestLine(r)) => Some(Message::Request(Request { + headers: message.headers, + request_line: (r, message.top_line.clone()), + body: body, + })), + nom::IResult::Done(_, TopLine::StatusLine(s)) => Some(Message::Response(Response { + headers: message.headers, + status_line: (s, message.top_line.clone()), + body: body, + })), + result => { + warn!("Failed to parse top line: {:?}", result); + None + } + } + } + + fn new_with_body(message: PartialMessage, body: BytesMut) -> Option { + Message::parse(message, Some(body)) + } + + fn as_bytes<'a>(&'a self) -> &'a [u8] { + match self { + &Message::Request(ref r) => r.as_bytes(), + &Message::Response(ref r) => r.as_bytes(), + } + } +} + +impl Decoder for SipCodec { + type Item = Message; + type Error = io::Error; + + fn decode(&mut self, buf: &mut BytesMut) -> io::Result> { + if let Some(_) = self.message { + trace!("Gathering body"); + + let length = self.message.iter().map(|m| m.body_length()).next().unwrap(); + + if length > buf.len() { + return Ok(None); + } else if let Some(message) = + Message::new_with_body(self.message.take().unwrap(), buf.split_to(length)) + { + return Ok(Some(message)); + } else { + warn!("Failed to parse message with no body!"); + } + } + + self.parse_message(buf) + } +} + +impl Encoder for SipCodec { + type Item = Message; + type Error = io::Error; + + fn encode(&mut self, msg: Message, buf: &mut BytesMut) -> io::Result<()> { + buf.extend(msg.as_bytes()); + Ok(()) + } +}