Skip to content

Instantly share code, notes, and snippets.

@m4rw3r
Last active August 29, 2015 14:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save m4rw3r/0dd154d232abd0f3d4cf to your computer and use it in GitHub Desktop.
Save m4rw3r/0dd154d232abd0f3d4cf to your computer and use it in GitHub Desktop.
Version of the attoparsec benchmark for parsing HTTP header dumps writtien in rust for the nom parser library.
#[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 {
c < 128 && c > 31 && b"()<>@,;:\\\"/[]?={} \t".iter().position(|&i| i == c).is_none()
}
fn not_line_ending(c: u8) -> bool {
c != b'\r' && c != b'\n'
}
fn is_space(c: u8) -> bool {
c == b' '
}
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(&'a [u8]) -> Request<'a>, chain!(
method: filter!(is_token) ~
filter!(is_space) ~
url: take_until_and_consume!(" ") ~
version: http_version ~
line_ending,
|| Request {
method: method,
uri: url,
version: version,
}));
named!(http_version, chain!(
tag!("HTTP/") ~
version: filter!(is_version),
|| version));
named!(message_header_value, chain!(
many1!(alt!(tag!(" ") | tag!("\t"))) ~
data: filter!(not_line_ending) ~
line_ending,
|| data));
named!(message_header(&'a [u8]) -> Header<'a>, chain!(
name: filter!(is_token) ~
tag!(":") ~
values: many1!(message_header_value),
|| Header {
name: name,
value: values,
}));
named!(request(&'a [u8]) -> (Request<'a>, Vec<Header<'a>>), chain!(
req: request_line ~
h: many1!(message_header) ~
tag!("\r\n"),
|| (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