Skip to content

Instantly share code, notes, and snippets.

@Geal
Last active September 8, 2015 15:36
Show Gist options
  • Save Geal/74723635420d8adc8031 to your computer and use it in GitHub Desktop.
Save Geal/74723635420d8adc8031 to your computer and use it in GitHub Desktop.
nom HTTP parsing benchmark (build with nom >= 0.4.0)
#![feature(test)]
extern crate test;
use test::Bencher;
#[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 {
// roughly follows the order of ascii chars: "\"(),/:;<=>?@[\\]{} \t"
c < 128 && c > 32 && c != b'\t' && c != b'"' && c != b'(' && c != b')' &&
c != b',' && c != b'/' && !(c > 57 && c < 65) && !(c > 90 && c < 94) &&
c != b'{' && c != b'}'
}
fn not_line_ending(c: u8) -> bool {
c != b'\r' && c != b'\n'
}
fn is_not_space(c: u8) -> bool { c != b' ' }
fn is_horizontal_space(c: u8) -> bool { c == b' ' || c == b'\t' }
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: 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(&'a [u8]) -> Header<'a>, chain!(
name: take_while1!(is_token) ~
char!(':') ~
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;
println!("{:?}", request(buf));
loop { request(buf); }
}
#[bench]
fn bench_http(b: &mut Bencher) {
let data = include_bytes!("../http-requests.txt");
b.iter(|| {
if let IResult::Done(_,res) = many0!(&data[..], request) {
let c = res.len();
c
} else { 0 }
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment