Rocket/benchmarks/src/routing.rs

130 lines
4.1 KiB
Rust
Raw Normal View History

use std::collections::hash_set::HashSet;
use criterion::{criterion_group, Criterion};
use rocket::{route, config, Request, Data, Route, Config};
use rocket::http::{Method, RawStr, ContentType, Accept, Status};
use rocket::local::blocking::{Client, LocalRequest};
fn dummy_handler<'r>(req: &'r Request, _: Data<'r>) -> route::BoxFuture<'r> {
route::Outcome::from(req, ()).pin()
}
fn parse_routes_table(table: &str) -> Vec<Route> {
let mut routes = vec![];
for line in table.split("\n").filter(|s| !s.is_empty()) {
let mut components = line.split(" ");
let method: Method = components.next().expect("c").parse().expect("method");
let uri: &str = components.next().unwrap();
let (mut rank, mut name, mut format) = (None, None, None);
for component in components {
match component {
c if c.starts_with('[') => rank = c.trim_matches(&['[', ']'][..]).parse().ok(),
c if c.starts_with('(') => name = Some(c.trim_matches(&['(', ')'][..])),
c => format = c.parse().ok(),
}
}
let mut route = Route::new(method, uri, dummy_handler);
if let Some(rank) = rank {
route.rank = rank;
}
route.format = format;
route.name = name.map(|s| s.to_string().into());
routes.push(route);
}
routes
}
fn generate_matching_requests<'c>(client: &'c Client, routes: &[Route]) -> Vec<LocalRequest<'c>> {
fn staticify_segment(segment: &RawStr) -> &str {
segment.as_str().trim_matches(&['<', '>', '.', '_'][..])
}
fn request_for_route<'c>(client: &'c Client, route: &Route) -> LocalRequest<'c> {
let path = route.uri.path()
.raw_segments()
.map(staticify_segment)
.collect::<Vec<_>>()
.join("/");
let query = route.uri.query()
.map(|q| q.raw_segments())
.into_iter()
.flatten()
.map(staticify_segment)
.collect::<Vec<_>>()
.join("&");
let uri = format!("/{}?{}", path, query);
let mut req = client.req(route.method, uri);
if let Some(ref format) = route.format {
if let Some(true) = route.method.allows_request_body() {
req.add_header(ContentType::from(format.clone()));
} else {
req.add_header(Accept::from(format.clone()));
}
}
req
}
routes.iter()
.map(|route| request_for_route(client, route))
.collect()
}
fn client(routes: Vec<Route>) -> Client {
let config = Config {
profile: Config::RELEASE_PROFILE,
// log_level: rocket::config::LogLevel::Off,
cli_colors: config::CliColors::Never,
Support QUIC and HTTP/3. This commit adds support for HTTP/3 and QUIC under a disabled-by-default feature `http3-preview`. The current implementation depends on modified versions of h3 and s2n-quic-h3 which will need to be upstreamed and published before a release is possible. During the course of development various facets of Rocket's internal connection handling and recent listener APIs were improved. The complete list of changes included in this PR is: * A `shutdown` module was introduced. * `config::Shutdown` was renamed to `ShutdownConfig` and moved to `shutdown` while being re-exported from `config`. * `ListenerAddr` is now called `Endpoint`. Various methods which previously referred to "addresses" now refer to "endpoints". * `Rocket::endpoint()` was renamed to `Rocket::endpoints()` and now returns an iterator over the endpoints Rocket is listening on. * `Endpoint` acquired various query utility methods. * The `{set_}remote()` methods now take/produce `Endpoint`s. * `TlsBindable` only accepts single-phase internal interfaces. * Bind error messages include candidate endpoint info when possible. * The warning message when a secret key is not configured now includes information about its effect on private cookies. Internal changes include: * Config module tests were moved to `config/tests.rs`. * The cancellable I/O implementation was significantly simplified. * The `TripWire` implementation was simplified. * Individual shutdown stages can now be awaited on via `Stages`. * The `Shield` implementation was simplified. Resolves #2723.
2024-03-19 03:19:00 +00:00
shutdown: config::ShutdownConfig {
ctrlc: false,
#[cfg(unix)]
signals: HashSet::new(),
..Default::default()
},
..Default::default()
};
match Client::untracked(rocket::custom(config).mount("/", routes)) {
Ok(client) => client,
Err(e) => {
drop(e);
panic!("bad launch")
}
}
}
pub fn bench_rust_lang_routes(c: &mut Criterion) {
let table = include_str!("../static/rust-lang.routes");
let routes = parse_routes_table(table);
let client = client(routes.clone());
let requests = generate_matching_requests(&client, &routes);
c.bench_function("rust-lang.routes", |b| b.iter(|| {
for request in requests.clone() {
let response = request.dispatch();
assert_eq!(response.status(), Status::Ok);
}
}));
}
pub fn bench_bitwarden_routes(c: &mut Criterion) {
let table = include_str!("../static/bitwarden_rs.routes");
let routes = parse_routes_table(table);
let client = client(routes.clone());
let requests = generate_matching_requests(&client, &routes);
c.bench_function("bitwarden_rs.routes", |b| b.iter(|| {
for request in requests.clone() {
let response = request.dispatch();
assert_eq!(response.status(), Status::Ok);
}
}));
}
criterion_group!(routing, bench_rust_lang_routes, bench_bitwarden_routes);