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