use criterion::{Criterion, black_box, criterion_group, criterion_main};
use std::str::FromStr;
use httpio::enums::header::http_header::HttpHeader;
use httpio::enums::http_body::HttpBody;
use httpio::structures::header::header_list::HttpHeaderList;
fn bench_header_list_add(c: &mut Criterion) {
let mut group = c.benchmark_group("header_list_add");
let known_header = HttpHeader::from_str("Content-Type: application/json").unwrap();
let generic_header = HttpHeader::from_str("X-Custom-Header: some-value").unwrap();
group.bench_function("known_header", |b| {
let mut list = HttpHeaderList::default();
b.iter(|| {
list.add(black_box(known_header.clone()));
});
});
group.bench_function("generic_header", |b| {
let mut list = HttpHeaderList::default();
b.iter(|| {
list.add(black_box(generic_header.clone()));
});
});
group.bench_function("multiple_headers", |b| {
let headers = vec![
HttpHeader::from_str("Content-Type: application/json").unwrap(),
HttpHeader::from_str("Content-Length: 100").unwrap(),
HttpHeader::from_str("Host: example.com").unwrap(),
HttpHeader::from_str("X-Custom-1: value1").unwrap(),
HttpHeader::from_str("X-Custom-2: value2").unwrap(),
];
b.iter(|| {
let mut list = HttpHeaderList::default();
for header in &headers {
list.add(black_box(header.clone()));
}
});
});
group.finish();
}
fn bench_request_builder_new(c: &mut Criterion) {
let mut group = c.benchmark_group("request_builder_new");
use httpio::enums::http_version::HttpVersion;
use httpio::structures::http_request_builder::HttpRequestBuilder;
let empty_headers = HttpHeaderList::default();
let some_headers: HttpHeaderList = vec![
HttpHeader::from_str("Accept: application/json").unwrap(),
HttpHeader::from_str("Authorization: Bearer token123").unwrap(),
]
.into();
group.bench_function("empty_headers", |b| {
b.iter(|| {
HttpRequestBuilder::new(
HttpVersion::Http11,
black_box(empty_headers.clone()),
"example.com",
)
});
});
group.bench_function("with_headers", |b| {
b.iter(|| {
HttpRequestBuilder::new(
HttpVersion::Http11,
black_box(some_headers.clone()),
"example.com",
)
});
});
group.finish();
}
fn bench_request_builder_build(c: &mut Criterion) {
let mut group = c.benchmark_group("request_builder_build");
use httpio::enums::http_request_method::HttpRequestMethod;
use httpio::enums::http_version::HttpVersion;
use httpio::structures::http_request_builder::HttpRequestBuilder;
let builder = HttpRequestBuilder::new(
HttpVersion::Http11,
HttpHeaderList::default(),
"example.com",
);
let empty_headers = HttpHeaderList::default();
let some_headers: HttpHeaderList = vec![
HttpHeader::from_str("Accept: application/json").unwrap(),
HttpHeader::from_str("X-Request-ID: abc123").unwrap(),
]
.into();
let small_body = HttpBody::Content(b"test".to_vec());
let medium_body = HttpBody::Content(vec![b'x'; 1024]);
group.bench_function("empty_headers_no_body", |b| {
b.iter(|| {
builder.build_request(
HttpRequestMethod::Get,
"/api/test",
black_box(empty_headers.clone()),
HttpBody::None,
)
});
});
group.bench_function("with_headers_no_body", |b| {
b.iter(|| {
builder.build_request(
HttpRequestMethod::Get,
"/api/test",
black_box(some_headers.clone()),
HttpBody::None,
)
});
});
group.bench_function("with_headers_small_body", |b| {
b.iter(|| {
builder.build_request(
HttpRequestMethod::Post,
"/api/test",
black_box(some_headers.clone()),
black_box(small_body.clone()),
)
});
});
group.bench_function("with_headers_medium_body", |b| {
b.iter(|| {
builder.build_request(
HttpRequestMethod::Post,
"/api/test",
black_box(some_headers.clone()),
black_box(medium_body.clone()),
)
});
});
group.finish();
}
fn bench_body_part_as_bytes(c: &mut Criterion) {
let mut group = c.benchmark_group("body_part_as_bytes");
use httpio::structures::http_body_part::HttpBodyPart;
let part_no_headers = HttpBodyPart {
headers: HttpHeaderList::default(),
content: b"Hello, World!".to_vec(),
};
let part_with_headers = HttpBodyPart {
headers: vec![
HttpHeader::from_str("Content-Type: text/plain").unwrap(),
HttpHeader::from_str("Content-Disposition: inline").unwrap(),
]
.into(),
content: b"Hello, World!".to_vec(),
};
let part_large_content = HttpBodyPart {
headers: vec![HttpHeader::from_str("Content-Type: application/octet-stream").unwrap()]
.into(),
content: vec![b'x'; 10000],
};
group.bench_function("no_headers_small", |b| {
b.iter(|| part_no_headers.as_bytes())
});
group.bench_function("with_headers_small", |b| {
b.iter(|| part_with_headers.as_bytes())
});
group.bench_function("large_content", |b| {
b.iter(|| part_large_content.as_bytes())
});
group.finish();
}
fn bench_multipart_as_bytes(c: &mut Criterion) {
let mut group = c.benchmark_group("multipart_as_bytes");
use httpio::structures::http_body_part::HttpBodyPart;
use httpio::structures::http_multipart_body::HttpMultipartBody;
let small_multipart = HttpMultipartBody {
parts: vec![
HttpBodyPart {
headers: vec![HttpHeader::from_str("Content-Type: text/plain").unwrap()].into(),
content: b"Part 1 content".to_vec(),
},
HttpBodyPart {
headers: vec![HttpHeader::from_str("Content-Type: text/plain").unwrap()].into(),
content: b"Part 2 content".to_vec(),
},
],
boundary: "boundary123".to_string(),
subtype: "form-data".to_string(),
preamble: vec![],
epilogue: vec![],
};
let medium_multipart = HttpMultipartBody {
parts: (0..10)
.map(|i| HttpBodyPart {
headers: vec![HttpHeader::from_str("Content-Type: text/plain").unwrap()].into(),
content: format!("Part {} content with some data", i).into_bytes(),
})
.collect(),
boundary: "boundary123".to_string(),
subtype: "form-data".to_string(),
preamble: vec![],
epilogue: vec![],
};
let large_multipart = HttpMultipartBody {
parts: (0..5)
.map(|_i| HttpBodyPart {
headers: vec![
HttpHeader::from_str("Content-Type: application/octet-stream").unwrap(),
]
.into(),
content: vec![b'x'; 2000],
})
.collect(),
boundary: "boundary123".to_string(),
subtype: "form-data".to_string(),
preamble: vec![],
epilogue: vec![],
};
group.bench_function("small_2_parts", |b| b.iter(|| small_multipart.as_bytes()));
group.bench_function("medium_10_parts", |b| {
b.iter(|| medium_multipart.as_bytes())
});
group.bench_function("large_5_parts_10kb", |b| {
b.iter(|| large_multipart.as_bytes())
});
group.finish();
}
fn bench_header_list_parsing(c: &mut Criterion) {
let mut group = c.benchmark_group("header_list_parsing");
let header_strings = vec![
"Content-Type: application/json",
"Content-Length: 12345",
"Host: example.com",
"Accept: */*",
"Accept-Encoding: gzip, deflate",
"User-Agent: benchmark/1.0",
"Connection: keep-alive",
"Cache-Control: no-cache",
"X-Request-ID: abc123",
"Authorization: Bearer token",
];
group.bench_function("parse_3_headers", |b| {
let headers = &header_strings[..3];
b.iter(|| {
let mut list = HttpHeaderList::default();
for header_str in headers {
let header = HttpHeader::from_str(black_box(header_str)).unwrap();
list.add(header);
}
});
});
group.bench_function("parse_10_headers", |b| {
b.iter(|| {
let mut list = HttpHeaderList::default();
for header_str in &header_strings {
let header = HttpHeader::from_str(black_box(header_str)).unwrap();
list.add(header);
}
});
});
group.finish();
}
criterion_group!(
benches,
bench_header_list_add,
bench_request_builder_new,
bench_request_builder_build,
bench_body_part_as_bytes,
bench_multipart_as_bytes,
bench_header_list_parsing,
);
criterion_main!(benches);