| #[macro_use] | |
| extern crate nom; | |
| use nom::IResult; | |
| use std::env; | |
| use std::fs::File; | |
| #[derive(Debug)] | |
| struct Request<'a> { | |
| method: &'a [u8], | |
| uri: &'a [u8], | |
| version: &'a [u8], | |
| } | |
| #[derive(Debug)] | |
| struct Header<'a> { | |
| name: &'a [u8], | |
| value: Vec<&'a [u8]>, | |
| } | |
| fn is_token(c: u8) -> bool { | |
| match c { | |
| 128...255 => false, | |
| 0...31 => false, | |
| b'(' => false, | |
| b')' => false, | |
| b'<' => false, | |
| b'>' => false, | |
| b'@' => false, | |
| b',' => false, | |
| b';' => false, | |
| b':' => false, | |
| b'\\' => false, | |
| b'"' => false, | |
| b'/' => false, | |
| b'[' => false, | |
| b']' => false, | |
| b'?' => false, | |
| b'=' => false, | |
| b'{' => false, | |
| b'}' => false, | |
| b' ' => false, | |
| _ => true, | |
| } | |
| } | |
| fn not_line_ending(c: u8) -> bool { | |
| c != b'\r' && c != b'\n' | |
| } | |
| fn is_space(c: u8) -> bool { | |
| c == b' ' | |
| } | |
| fn is_not_space(c: u8) -> bool { c != b' ' } | |
| fn is_horizontal_space(c: u8) -> bool { c == b' ' || c == b'\t' } | |
| fn is_version(c: u8) -> bool { | |
| c >= b'0' && c <= b'9' || c == b'.' | |
| } | |
| named!(line_ending, alt!(tag!("\n") | tag!("\r\n"))); | |
| named!(request_line(&[u8]) -> Request, chain!( | |
| method: take_while1!(is_token) ~ | |
| take_while1!(is_space) ~ | |
| url: take_while1!(is_not_space) ~ | |
| take_while1!(is_space) ~ | |
| version: http_version ~ | |
| line_ending, | |
| || Request { | |
| method: method, | |
| uri: url, | |
| version: version, | |
| })); | |
| named!(http_version, chain!( | |
| tag!("HTTP/") ~ | |
| version: take_while1!(is_version), | |
| || version)); | |
| named!(message_header_value, chain!( | |
| take_while1!(is_horizontal_space) ~ | |
| data: take_while1!(not_line_ending) ~ | |
| line_ending, | |
| || data)); | |
| named!(message_header(&[u8]) -> Header, chain!( | |
| name: take_while1!(is_token) ~ | |
| char!(':') ~ | |
| values: many1!(message_header_value), | |
| || Header { | |
| name: name, | |
| value: values, | |
| })); | |
| named!(request(&[u8]) -> (Request, Vec<Header>), chain!( | |
| req: request_line ~ | |
| h: many1!(message_header) ~ | |
| line_ending, | |
| || (req, h))); | |
| fn main() { | |
| let mut contents: Vec<u8> = Vec::new(); | |
| { | |
| use std::io::Read; | |
| let mut file = File::open(env::args().nth(1).expect("File to read")).ok().expect("Failed to open file"); | |
| let _ = file.read_to_end(&mut contents).unwrap(); | |
| } | |
| let mut buf = &contents[..]; | |
| let mut i = 0; | |
| loop { | |
| match request(buf) { | |
| IResult::Done(b, _) => { | |
| buf = b; | |
| i = i + 1; | |
| if b.is_empty() { | |
| break; | |
| } | |
| }, | |
| IResult::Error(e) => panic!("{:?}", e), | |
| IResult::Incomplete(_) => panic!("Incomplete!"), | |
| } | |
| } | |
| println!("{}", i); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment