use std::io::Read;
use std::mem;
use std::str;
use std::convert::From;
use std::default::Default;
use std::net::TcpStream;
use std::fmt;
use http_muncher::{Parser, ParserHandler};
#[derive(Debug)]
pub struct Request {
version: (u16, u16),
pub method: String,
pub path: String,
pub headers: Vec<(String, String)>,
pub body: Vec<u8>,
error: Option<String>,
is_parsed: bool,
last_header_field: Option<String>,
last_header_value: Option<String>,
}
impl Request {
pub fn is_ok(&self) -> bool {
self.error.is_none()
}
pub fn is_err(&self) -> bool {
self.error.is_some()
}
pub fn error(&self) -> Option<&String> {
self.error.as_ref()
}
pub fn find_header(&self, searched_field: &str) -> Option<&String> {
self.headers.iter().find(|&&(ref field, _)| field == searched_field).and_then(|&(_, ref value)| Some(value))
}
fn is_parsed(&self) -> bool {
self.is_parsed
}
fn record_last_header(&mut self) {
if self.last_header_field.is_some() && self.last_header_value.is_some() {
let last_header_field = mem::replace(&mut self.last_header_field, None).unwrap();
let last_header_value = mem::replace(&mut self.last_header_value, None).unwrap();
self.headers.push((last_header_field.to_lowercase(), last_header_value));
}
}
}
impl Default for Request {
fn default() -> Self {
Request {
version: (1, 1),
method: String::new(),
path: String::new(),
headers: Vec::new(),
body: Vec::new(),
error: None,
is_parsed: false,
last_header_field: None,
last_header_value: None,
}
}
}
impl<'a> From<&'a mut TcpStream> for Request {
fn from(stream: &mut TcpStream) -> Self {
let mut request = Request::default();
let mut parser = Parser::request();
let mut first_read = true;
loop {
if request.is_parsed() { break; }
let mut buffer = [0; 1024];
let read_length = stream.read(&mut buffer).unwrap_or(0);
if read_length == 0 {
if first_read { request.error = Some("Nothing to read.".to_string()); }
break;
}
first_read = false;
let parse_length = parser.parse(&mut request, (&buffer).chunks(read_length).nth(0).unwrap());
if parse_length == 0 || parser.has_error() { break; }
}
if parser.has_error() {
request.error = Some(parser.error().to_string());
} else {
request.version = parser.http_version();
request.method = parser.http_method().to_string();
}
request
}
}
impl ParserHandler for Request {
fn on_message_begin(&mut self, parser: &mut Parser) -> bool {
!parser.has_error()
}
fn on_url(&mut self, parser: &mut Parser, value: &[u8]) -> bool {
self.path.push_str(str::from_utf8(value).unwrap());
!parser.has_error()
}
fn on_header_field(&mut self, parser: &mut Parser, value: &[u8]) -> bool {
self.record_last_header();
if self.last_header_field.is_none() {
self.last_header_field = Some(String::new());
}
(*self.last_header_field.as_mut().unwrap()).push_str(str::from_utf8(value).unwrap());
!parser.has_error()
}
fn on_header_value(&mut self, parser: &mut Parser, value: &[u8]) -> bool {
if self.last_header_value.is_none() {
self.last_header_value = Some(String::new());
}
(*self.last_header_value.as_mut().unwrap()).push_str(str::from_utf8(value).unwrap());
!parser.has_error()
}
fn on_headers_complete(&mut self, parser: &mut Parser) -> bool {
self.record_last_header();
!parser.has_error()
}
fn on_body(&mut self, parser: &mut Parser, value: &[u8]) -> bool {
self.body.extend(value);
!parser.has_error()
}
fn on_message_complete(&mut self, parser: &mut Parser) -> bool {
self.is_parsed = true;
!parser.has_error()
}
}
impl fmt::Display for Request {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut formatted = String::new();
formatted.push_str("\r\n");
formatted.push_str(&self.method);
formatted.push_str(" ");
formatted.push_str(&self.path);
formatted.push_str("\r\n");
for &(ref key, ref value) in &self.headers {
formatted.push_str(key);
formatted.push_str(": ");
formatted.push_str(value);
formatted.push_str("\r\n");
}
if self.body.len() > 0 {
formatted.push_str(&String::from_utf8_lossy(&self.body));
formatted.push_str("\r\n");
}
write!(f, "{}", formatted)
}
}