Skip to content

Commit e2bbecb

Browse files
committed
router: represent methods as http::Method
Currently, the `Router` stores HTTP methods for an endpoint as `String`s. This is a bit unfortunate, as it means the already-parsed `http::Method` for each request has to be un-parsed back into a `String` to look it up in the map, allocating a new `String` each time and converting it to uppercases to perform the lookup. Switching to the typed `http::Method` representation should make things a bit more efficient (especially as `Method` also implements inline storage for extension methods up to a certain length) and provide additional type safety. This does require switching from a `BTreeMap` of strings to handlers to a `HashMap` of `Method`s to handlers, as `Method` does not implement `Ord`/`PartialOrd`, but ordering shouldn't matter here.
1 parent 82c8fe4 commit e2bbecb

File tree

3 files changed

+23
-24
lines changed

3 files changed

+23
-24
lines changed

dropshot/src/api_description.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -670,15 +670,15 @@ impl<Context: ServerContext> ApiDescription<Context> {
670670
_ => panic!("reference not expected"),
671671
};
672672

673-
let method_ref = match &method[..] {
674-
"GET" => &mut pathitem.get,
675-
"PUT" => &mut pathitem.put,
676-
"POST" => &mut pathitem.post,
677-
"DELETE" => &mut pathitem.delete,
678-
"OPTIONS" => &mut pathitem.options,
679-
"HEAD" => &mut pathitem.head,
680-
"PATCH" => &mut pathitem.patch,
681-
"TRACE" => &mut pathitem.trace,
673+
let method_ref = match method {
674+
http::Method::GET => &mut pathitem.get,
675+
http::Method::PUT => &mut pathitem.put,
676+
http::Method::POST => &mut pathitem.post,
677+
http::Method::DELETE => &mut pathitem.delete,
678+
http::Method::OPTIONS => &mut pathitem.options,
679+
http::Method::HEAD => &mut pathitem.head,
680+
http::Method::PATCH => &mut pathitem.patch,
681+
http::Method::TRACE => &mut pathitem.trace,
682682
other => panic!("unexpected method `{}`", other),
683683
};
684684
let mut operation = openapiv3::Operation::default();

dropshot/src/router.rs

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use http::StatusCode;
1414
use percent_encoding::percent_decode_str;
1515
use std::collections::BTreeMap;
1616
use std::collections::BTreeSet;
17+
use std::collections::HashMap;
1718
use std::sync::Arc;
1819

1920
/// `HttpRouter` is a simple data structure for routing incoming HTTP requests to
@@ -81,7 +82,7 @@ pub struct HttpRouter<Context: ServerContext> {
8182
#[derive(Debug)]
8283
struct HttpRouterNode<Context: ServerContext> {
8384
/// Handlers, etc. for each of the HTTP methods defined for this node.
84-
methods: BTreeMap<String, ApiEndpoint<Context>>,
85+
methods: HashMap<Method, ApiEndpoint<Context>>,
8586
/// Edges linking to child nodes.
8687
edges: Option<HttpRouterEdges<Context>>,
8788
}
@@ -217,7 +218,7 @@ pub struct RouterLookupResult<Context: ServerContext> {
217218

218219
impl<Context: ServerContext> HttpRouterNode<Context> {
219220
pub fn new() -> Self {
220-
HttpRouterNode { methods: BTreeMap::new(), edges: None }
221+
HttpRouterNode { methods: HashMap::new(), edges: None }
221222
}
222223
}
223224

@@ -385,16 +386,15 @@ impl<Context: ServerContext> HttpRouter<Context> {
385386
};
386387
}
387388

388-
let methodname = method.as_str().to_uppercase();
389-
if node.methods.contains_key(&methodname) {
389+
if node.methods.contains_key(&method) {
390390
panic!(
391391
"URI path \"{}\": attempted to create duplicate route for \
392392
method \"{}\"",
393393
path, method,
394394
);
395395
}
396396

397-
node.methods.insert(methodname, endpoint);
397+
node.methods.insert(method, endpoint);
398398
}
399399

400400
/// Look up the route handler for an HTTP request having method `method` and
@@ -478,9 +478,8 @@ impl<Context: ServerContext> HttpRouter<Context> {
478478
));
479479
}
480480

481-
let methodname = method.as_str().to_uppercase();
482481
node.methods
483-
.get(&methodname)
482+
.get(&method)
484483
.map(|handler| RouterLookupResult {
485484
handler: Arc::clone(&handler.handler),
486485
operation_id: handler.operation_id.clone(),
@@ -512,7 +511,7 @@ fn insert_var(
512511
}
513512

514513
impl<'a, Context: ServerContext> IntoIterator for &'a HttpRouter<Context> {
515-
type Item = (String, String, &'a ApiEndpoint<Context>);
514+
type Item = (String, Method, &'a ApiEndpoint<Context>);
516515
type IntoIter = HttpRouterIter<'a, Context>;
517516
fn into_iter(self) -> Self::IntoIter {
518517
HttpRouterIter::new(self)
@@ -529,7 +528,7 @@ impl<'a, Context: ServerContext> IntoIterator for &'a HttpRouter<Context> {
529528
/// blank string and an iterator over the root node's children.
530529
pub struct HttpRouterIter<'a, Context: ServerContext> {
531530
method:
532-
Box<dyn Iterator<Item = (&'a String, &'a ApiEndpoint<Context>)> + 'a>,
531+
Box<dyn Iterator<Item = (&'a Method, &'a ApiEndpoint<Context>)> + 'a>,
533532
path: Vec<(PathSegment, Box<PathIter<'a, Context>>)>,
534533
}
535534
type PathIter<'a, Context> =
@@ -592,7 +591,7 @@ impl<'a, Context: ServerContext> HttpRouterIter<'a, Context> {
592591
}
593592

594593
impl<'a, Context: ServerContext> Iterator for HttpRouterIter<'a, Context> {
595-
type Item = (String, String, &'a ApiEndpoint<Context>);
594+
type Item = (String, Method, &'a ApiEndpoint<Context>);
596595

597596
fn next(&mut self) -> Option<Self::Item> {
598597
// If there are no path components left then we've reached the end of
@@ -1309,10 +1308,10 @@ mod test {
13091308
assert_eq!(
13101309
ret,
13111310
vec![
1312-
("/".to_string(), "GET".to_string(),),
1311+
("/".to_string(), http::Method::GET,),
13131312
(
13141313
"/projects/{project_id}/instances".to_string(),
1315-
"GET".to_string(),
1314+
http::Method::GET,
13161315
),
13171316
]
13181317
);
@@ -1335,8 +1334,8 @@ mod test {
13351334
assert_eq!(
13361335
ret,
13371336
vec![
1338-
("/".to_string(), "GET".to_string(),),
1339-
("/".to_string(), "POST".to_string(),),
1337+
("/".to_string(), http::Method::GET,),
1338+
("/".to_string(), http::Method::POST),
13401339
]
13411340
);
13421341
}

dropshot/src/server.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ impl<C: ServerContext> HttpServerStarter<C> {
206206

207207
for (path, method, _) in &app_state.router {
208208
debug!(&log, "registered endpoint";
209-
"method" => &method,
209+
"method" => %method,
210210
"path" => &path
211211
);
212212
}

0 commit comments

Comments
 (0)