use http_muncher;
use token::HttpToken;
use parser_handler::ParserHandler;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ParserError {
pub error: String,
}
enum ParserType {
Request,
Response,
}
pub struct Parser {
parser: http_muncher::Parser<ParserHandler>,
parser_type: ParserType,
error: Option<ParserError>,
first_line_sent: bool,
}
impl Parser {
pub fn request() -> Parser {
Parser {
parser: http_muncher::Parser::request(ParserHandler::default()),
parser_type: ParserType::Request,
error: None,
first_line_sent: false,
}
}
pub fn response() -> Parser {
Parser {
parser: http_muncher::Parser::response(ParserHandler::default()),
parser_type: ParserType::Response,
error: None,
first_line_sent: false,
}
}
pub fn next_token(&mut self, data: Option<&[u8]>)
-> (Result<Option<HttpToken>, ParserError>, usize) {
let mut nparsed = 0;
if self.error.is_none() {
if let Some(data) = data {
if data.len() > 0 {
nparsed = self.parser.parse(data);
if self.parser.has_error() {
self.error = Some(ParserError {
error: self.parser.error().to_string(),
});
}
}
}
}
if self.parser.get().tokens.front().is_some() && !self.first_line_sent {
self.first_line_sent = true;
match self.parser_type {
ParserType::Request => {
return (Ok(Some(HttpToken::Method(self.parser.http_method()
.to_string()))),
nparsed);
}
ParserType::Response => {
let token = match self.parser.get().tokens.pop_front()
.unwrap() {
HttpToken::Status(_, reason) => {
HttpToken::Status(self.parser.status_code(),
reason)
}
_ => unreachable!(),
};
return (Ok(Some(token)), nparsed);
}
}
}
if let Some(token) = self.parser.get().tokens.pop_front() {
if token == HttpToken::EndOfMessage {
self.first_line_sent = false;
}
return (Ok(Some(token)), nparsed);
} else {
if let Some(ref e) = self.error {
return (Err(e.clone()), nparsed);
} else {
return (Ok(None), nparsed);
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use token::HttpToken;
#[test]
fn simple() {
let mut parser = Parser::request();
let mut tokens = Vec::new();
let mut http_request: Vec<_> = b"GET /te".iter()
.cloned().collect();
loop {
let (t, nparsed) = parser.next_token(Some(&http_request));
http_request.drain(..nparsed);
if let Ok(Some(t)) = t {
tokens.push(t);
} else {
break;
}
}
http_request.extend(b"st HTTP/1.0\r\n\
Cont".iter().cloned());
loop {
let (t, nparsed) = parser.next_token(Some(&http_request));
http_request.drain(..nparsed);
if let Ok(Some(t)) = t {
tokens.push(t);
} else {
break;
}
}
http_request.extend(b"ent-Length: 00".iter().cloned());
loop {
let (t, nparsed) = parser.next_token(Some(&http_request));
http_request.drain(..nparsed);
if let Ok(Some(t)) = t {
tokens.push(t);
} else {
break;
}
}
http_request.extend(b"00\r\n\r\n".iter().cloned());
loop {
let (t, nparsed) = parser.next_token(Some(&http_request));
http_request.drain(..nparsed);
if let Ok(Some(t)) = t {
tokens.push(t);
} else {
break;
}
}
assert_eq!(tokens,
[HttpToken::Method("GET".to_string()),
HttpToken::Url("/test".to_string()),
HttpToken::Field("Content-Length".to_string(),
"0000".to_string()),
HttpToken::EndOfMessage]);
assert_eq!(parser.next_token(None), (Ok(None), 0));
}
}