http-pull-parser 0.1.4

A simple almost-pull-parser for HTTP
Documentation
use std::collections::VecDeque;
use http_parser::{CallbackResult, HttpParser, HttpParserCallback, ParseAction};
use token::HttpToken;

pub enum ParserType {
    Request,
    Response,
}

enum State {
    Default,
    Url(String),
    Field(String),
    Value(String, String),
}

fn to_string(bytes: &[u8]) -> String {
    String::from_utf8(bytes.iter().cloned().collect::<Vec<_>>()).unwrap()
}

pub struct ParserHandler {
    pub tokens: VecDeque<HttpToken>,
    pending_tokens: VecDeque<HttpToken>,
    reason_phrase: Option<String>,
    state: State,
    pub parser_type: ParserType,
}

impl ParserHandler {
    pub fn new(parser_type: ParserType) -> ParserHandler {
        ParserHandler {
            tokens: VecDeque::new(),
            pending_tokens: VecDeque::new(),
            reason_phrase: None,
            state: State::Default,
            parser_type: parser_type,
        }
    }
}

impl HttpParserCallback for ParserHandler {
    fn on_message_begin(&mut self, _parser: &mut HttpParser) -> CallbackResult {
        return Ok(ParseAction::None);
    }

    fn on_url(&mut self, _parser: &mut HttpParser, url: &[u8])
              -> CallbackResult {
        let url = to_string(url);
        match self.state {
            State::Default => self.state = State::Url(url),
            State::Url(ref mut buf) => buf.push_str(&url),
            _ => unreachable!(),
        }
        return Ok(ParseAction::None);
    }

    fn on_status(&mut self, _parser: &mut HttpParser, status: &[u8])
                 -> CallbackResult {
        let status = to_string(status);
        match self.reason_phrase {
            Some(ref mut buf) => buf.push_str(&status),
            None => self.reason_phrase = Some(status),
        }
        return Ok(ParseAction::None);
    }

    fn on_header_field(&mut self, _parser: &mut HttpParser,
                       field: &[u8]) -> CallbackResult {
        let field = to_string(field);
        let mut new_state = None;
        match self.state {
            State::Default => {
                new_state = Some(State::Field(field));
            }
            State::Url(ref mut url) => {
                let url = {
                    let mut t = String::new();
                    use std::mem;
                    mem::swap(&mut t, url);
                    t
                };
                self.pending_tokens.push_back(HttpToken::Url(url));
                new_state = Some(State::Field(field));
            }
            State::Field(ref mut buf) => buf.push_str(&field),
            State::Value(ref mut f, ref mut v) => {
                let f = {
                    let mut t = String::new();
                    use std::mem;
                    mem::swap(&mut t, f);
                    t
                };
                let v = {
                    let mut t = String::new();
                    use std::mem;
                    mem::swap(&mut t, v);
                    t
                };
                self.pending_tokens.push_back(HttpToken::Field(f, v));
                new_state = Some(State::Field(field));
            }
        }
        if let Some(state) = new_state.take() {
            self.state = state;
        }
        return Ok(ParseAction::None);
    }

    fn on_header_value(&mut self, _parser: &mut HttpParser,
                       value: &[u8]) -> CallbackResult {
        let value = to_string(value);
        let mut new_state = None;
        match self.state {
            State::Field(ref mut f) => {
                let f = {
                    let mut t = String::new();
                    use std::mem;
                    mem::swap(&mut t, f);
                    t
                };
                new_state = Some(State::Value(f, value));
            }
            State::Value(_, ref mut buf) => buf.push_str(&value),
            _ => unreachable!(),
        }
        if let Some(state) = new_state.take() {
            self.state = state;
        }
        return Ok(ParseAction::None);
    }

    fn on_headers_complete(&mut self, parser: &mut HttpParser)
                           -> CallbackResult {
        let mut new_state = None;
        if let State::Value(ref mut f, ref mut v) = self.state {
                let f = {
                    let mut t = String::new();
                    use std::mem;
                    mem::swap(&mut t, f);
                    t
                };
                let v = {
                    let mut t = String::new();
                    use std::mem;
                    mem::swap(&mut t, v);
                    t
                };
            self.pending_tokens.push_back(HttpToken::Field(f, v));
            new_state = Some(State::Default);
        }
        if let Some(state) = new_state.take() {
            self.state = state;
        }
        let t = match self.parser_type {
            ParserType::Request => {
                HttpToken::Method(parser.method.unwrap().to_string())
            }
            ParserType::Response => {
                HttpToken::Status(parser.status_code.unwrap(),
                                  self.reason_phrase.take().unwrap())
            }
        };
        self.tokens.push_back(t);
        self.tokens.append(&mut self.pending_tokens);
        return Ok(ParseAction::None);
    }

    fn on_body(&mut self, _parser: &mut HttpParser, body: &[u8])
               -> CallbackResult {
        self.tokens.push_back(HttpToken::Body(body.iter().cloned().collect()));
        return Ok(ParseAction::None);
    }

    fn on_message_complete(&mut self, _parser: &mut HttpParser)
                           -> CallbackResult {
        self.state = State::Default;
        self.tokens.push_back(HttpToken::EndOfMessage);
        return Ok(ParseAction::None);
    }
}