16855e09eSopenharmony_ci#![cfg_attr(rustfmt, rustfmt_skip)]
26855e09eSopenharmony_ci
36855e09eSopenharmony_ci#[global_allocator]
46855e09eSopenharmony_cistatic ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
56855e09eSopenharmony_ci
66855e09eSopenharmony_ciuse criterion::*;
76855e09eSopenharmony_ciuse nom::{IResult, bytes::complete::{tag, take_while1}, character::complete::{line_ending, char}, multi::many1};
86855e09eSopenharmony_ci
96855e09eSopenharmony_ci#[cfg_attr(rustfmt, rustfmt_skip)]
106855e09eSopenharmony_ci#[derive(Debug)]
116855e09eSopenharmony_cistruct Request<'a> {
126855e09eSopenharmony_ci  method:  &'a [u8],
136855e09eSopenharmony_ci  uri:     &'a [u8],
146855e09eSopenharmony_ci  version: &'a [u8],
156855e09eSopenharmony_ci}
166855e09eSopenharmony_ci
176855e09eSopenharmony_ci#[derive(Debug)]
186855e09eSopenharmony_cistruct Header<'a> {
196855e09eSopenharmony_ci  name: &'a [u8],
206855e09eSopenharmony_ci  value: Vec<&'a [u8]>,
216855e09eSopenharmony_ci}
226855e09eSopenharmony_ci
236855e09eSopenharmony_ci#[cfg_attr(rustfmt, rustfmt_skip)]
246855e09eSopenharmony_ci#[cfg_attr(feature = "cargo-clippy", allow(match_same_arms))]
256855e09eSopenharmony_cifn is_token(c: u8) -> bool {
266855e09eSopenharmony_ci  match c {
276855e09eSopenharmony_ci    128..=255 => false,
286855e09eSopenharmony_ci    0..=31    => false,
296855e09eSopenharmony_ci    b'('      => false,
306855e09eSopenharmony_ci    b')'      => false,
316855e09eSopenharmony_ci    b'<'      => false,
326855e09eSopenharmony_ci    b'>'      => false,
336855e09eSopenharmony_ci    b'@'      => false,
346855e09eSopenharmony_ci    b','      => false,
356855e09eSopenharmony_ci    b';'      => false,
366855e09eSopenharmony_ci    b':'      => false,
376855e09eSopenharmony_ci    b'\\'     => false,
386855e09eSopenharmony_ci    b'"'      => false,
396855e09eSopenharmony_ci    b'/'      => false,
406855e09eSopenharmony_ci    b'['      => false,
416855e09eSopenharmony_ci    b']'      => false,
426855e09eSopenharmony_ci    b'?'      => false,
436855e09eSopenharmony_ci    b'='      => false,
446855e09eSopenharmony_ci    b'{'      => false,
456855e09eSopenharmony_ci    b'}'      => false,
466855e09eSopenharmony_ci    b' '      => false,
476855e09eSopenharmony_ci    _         => true,
486855e09eSopenharmony_ci  }
496855e09eSopenharmony_ci}
506855e09eSopenharmony_ci
516855e09eSopenharmony_cifn not_line_ending(c: u8) -> bool {
526855e09eSopenharmony_ci  c != b'\r' && c != b'\n'
536855e09eSopenharmony_ci}
546855e09eSopenharmony_ci
556855e09eSopenharmony_cifn is_space(c: u8) -> bool {
566855e09eSopenharmony_ci  c == b' '
576855e09eSopenharmony_ci}
586855e09eSopenharmony_ci
596855e09eSopenharmony_cifn is_not_space(c: u8) -> bool {
606855e09eSopenharmony_ci  c != b' '
616855e09eSopenharmony_ci}
626855e09eSopenharmony_cifn is_horizontal_space(c: u8) -> bool {
636855e09eSopenharmony_ci  c == b' ' || c == b'\t'
646855e09eSopenharmony_ci}
656855e09eSopenharmony_ci
666855e09eSopenharmony_cifn is_version(c: u8) -> bool {
676855e09eSopenharmony_ci  c >= b'0' && c <= b'9' || c == b'.'
686855e09eSopenharmony_ci}
696855e09eSopenharmony_ci
706855e09eSopenharmony_cifn request_line(input: &[u8]) -> IResult<&[u8], Request<'_>> {
716855e09eSopenharmony_ci  let (input, method) = take_while1(is_token)(input)?;
726855e09eSopenharmony_ci  let (input, _) = take_while1(is_space)(input)?;
736855e09eSopenharmony_ci  let (input, uri) = take_while1(is_not_space)(input)?;
746855e09eSopenharmony_ci  let (input, _) = take_while1(is_space)(input)?;
756855e09eSopenharmony_ci  let (input, version) = http_version(input)?;
766855e09eSopenharmony_ci  let (input, _) = line_ending(input)?;
776855e09eSopenharmony_ci
786855e09eSopenharmony_ci  Ok((input, Request {method, uri, version}))
796855e09eSopenharmony_ci}
806855e09eSopenharmony_ci
816855e09eSopenharmony_cifn http_version(input: &[u8]) -> IResult<&[u8], &[u8]> {
826855e09eSopenharmony_ci  let (input, _) = tag("HTTP/")(input)?;
836855e09eSopenharmony_ci  let (input, version) = take_while1(is_version)(input)?;
846855e09eSopenharmony_ci
856855e09eSopenharmony_ci  Ok((input, version))
866855e09eSopenharmony_ci}
876855e09eSopenharmony_ci
886855e09eSopenharmony_cifn message_header_value(input: &[u8]) -> IResult<&[u8], &[u8]> {
896855e09eSopenharmony_ci  let (input, _) = take_while1(is_horizontal_space)(input)?;
906855e09eSopenharmony_ci  let (input, data) = take_while1(not_line_ending)(input)?;
916855e09eSopenharmony_ci  let (input, _) = line_ending(input)?;
926855e09eSopenharmony_ci
936855e09eSopenharmony_ci  Ok((input, data))
946855e09eSopenharmony_ci}
956855e09eSopenharmony_ci
966855e09eSopenharmony_cifn message_header(input: &[u8]) -> IResult<&[u8], Header<'_>> {
976855e09eSopenharmony_ci  let (input, name) = take_while1(is_token)(input)?;
986855e09eSopenharmony_ci  let (input, _) = char(':')(input)?;
996855e09eSopenharmony_ci  let (input, value) = many1(message_header_value)(input)?;
1006855e09eSopenharmony_ci
1016855e09eSopenharmony_ci  Ok((input, Header{ name, value }))
1026855e09eSopenharmony_ci}
1036855e09eSopenharmony_ci
1046855e09eSopenharmony_cifn request(input: &[u8]) -> IResult<&[u8], (Request<'_>, Vec<Header<'_>>)> {
1056855e09eSopenharmony_ci  let (input, req) = request_line(input)?;
1066855e09eSopenharmony_ci  let (input, h) = many1(message_header)(input)?;
1076855e09eSopenharmony_ci  let (input, _) = line_ending(input)?;
1086855e09eSopenharmony_ci
1096855e09eSopenharmony_ci  Ok((input, (req, h)))
1106855e09eSopenharmony_ci}
1116855e09eSopenharmony_ci
1126855e09eSopenharmony_ci
1136855e09eSopenharmony_cifn parse(data: &[u8]) -> Option<Vec<(Request<'_>, Vec<Header<'_>>)>> {
1146855e09eSopenharmony_ci  let mut buf = &data[..];
1156855e09eSopenharmony_ci  let mut v = Vec::new();
1166855e09eSopenharmony_ci  loop {
1176855e09eSopenharmony_ci    match request(buf) {
1186855e09eSopenharmony_ci      Ok((b, r)) => {
1196855e09eSopenharmony_ci        buf = b;
1206855e09eSopenharmony_ci        v.push(r);
1216855e09eSopenharmony_ci
1226855e09eSopenharmony_ci        if b.is_empty() {
1236855e09eSopenharmony_ci
1246855e09eSopenharmony_ci          //println!("{}", i);
1256855e09eSopenharmony_ci          break;
1266855e09eSopenharmony_ci        }
1276855e09eSopenharmony_ci      }
1286855e09eSopenharmony_ci      Err(e) => {
1296855e09eSopenharmony_ci        println!("error: {:?}", e);
1306855e09eSopenharmony_ci        return None;
1316855e09eSopenharmony_ci      },
1326855e09eSopenharmony_ci    }
1336855e09eSopenharmony_ci  }
1346855e09eSopenharmony_ci
1356855e09eSopenharmony_ci  Some(v)
1366855e09eSopenharmony_ci}
1376855e09eSopenharmony_ci
1386855e09eSopenharmony_ci/*
1396855e09eSopenharmony_ci#[bench]
1406855e09eSopenharmony_cifn small_test(b: &mut Bencher) {
1416855e09eSopenharmony_ci  let data = include_bytes!("../../http-requests.txt");
1426855e09eSopenharmony_ci  b.iter(||{
1436855e09eSopenharmony_ci    parse(data)
1446855e09eSopenharmony_ci  });
1456855e09eSopenharmony_ci}
1466855e09eSopenharmony_ci
1476855e09eSopenharmony_ci#[bench]
1486855e09eSopenharmony_cifn bigger_test(b: &mut Bencher) {
1496855e09eSopenharmony_ci  let data = include_bytes!("../../bigger.txt");
1506855e09eSopenharmony_ci  b.iter(||{
1516855e09eSopenharmony_ci    parse(data)
1526855e09eSopenharmony_ci  });
1536855e09eSopenharmony_ci}
1546855e09eSopenharmony_ci*/
1556855e09eSopenharmony_ci
1566855e09eSopenharmony_cifn one_test(c: &mut Criterion) {
1576855e09eSopenharmony_ci  let data = &b"GET / HTTP/1.1
1586855e09eSopenharmony_ciHost: www.reddit.com
1596855e09eSopenharmony_ciUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
1606855e09eSopenharmony_ciAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
1616855e09eSopenharmony_ciAccept-Language: en-us,en;q=0.5
1626855e09eSopenharmony_ciAccept-Encoding: gzip, deflate
1636855e09eSopenharmony_ciConnection: keep-alive
1646855e09eSopenharmony_ci
1656855e09eSopenharmony_ci"[..];
1666855e09eSopenharmony_ci
1676855e09eSopenharmony_ci  let mut http_group = c.benchmark_group("http");
1686855e09eSopenharmony_ci  http_group.throughput(Throughput::Bytes(data.len() as u64));
1696855e09eSopenharmony_ci  http_group.bench_with_input(
1706855e09eSopenharmony_ci    BenchmarkId::new("parse", data.len()),
1716855e09eSopenharmony_ci     data,
1726855e09eSopenharmony_ci      |b, data| {
1736855e09eSopenharmony_ci    b.iter(|| parse(data).unwrap());
1746855e09eSopenharmony_ci  });
1756855e09eSopenharmony_ci
1766855e09eSopenharmony_ci  http_group.finish();
1776855e09eSopenharmony_ci}
1786855e09eSopenharmony_ci
1796855e09eSopenharmony_ci/*
1806855e09eSopenharmony_cifn main() {
1816855e09eSopenharmony_ci  let mut contents: Vec<u8> = Vec::new();
1826855e09eSopenharmony_ci
1836855e09eSopenharmony_ci  {
1846855e09eSopenharmony_ci    use std::io::Read;
1856855e09eSopenharmony_ci
1866855e09eSopenharmony_ci    let mut file = File::open(env::args().nth(1).expect("File to read")).expect("Failed to open file");
1876855e09eSopenharmony_ci
1886855e09eSopenharmony_ci    let _ = file.read_to_end(&mut contents).unwrap();
1896855e09eSopenharmony_ci  }
1906855e09eSopenharmony_ci
1916855e09eSopenharmony_ci  let buf = &contents[..];
1926855e09eSopenharmony_ci  loop {
1936855e09eSopenharmony_ci    parse(buf);
1946855e09eSopenharmony_ci  }
1956855e09eSopenharmony_ci}
1966855e09eSopenharmony_ci*/
1976855e09eSopenharmony_ci
1986855e09eSopenharmony_cicriterion_group!(http, one_test);
1996855e09eSopenharmony_cicriterion_main!(http);
200