Skip to content

Commit

Permalink
Push RequestId setting into NewHandlerService
Browse files Browse the repository at this point in the history
This will ensure all Handler instances, not just Router are provided with
this functionality which is a reasonable default expectation.
  • Loading branch information
bradleybeddoes committed Jun 15, 2017
1 parent d107e8d commit 3450180
Show file tree
Hide file tree
Showing 4 changed files with 12 additions and 36 deletions.
7 changes: 5 additions & 2 deletions src/handler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use hyper;
use hyper::server;
use hyper::server::Request;
use futures::{future, Future};
use state::State;
use state::{State, set_request_id};
use std::io;
use std::sync::Arc;

Expand Down Expand Up @@ -129,13 +129,16 @@ impl<T> server::Service for NewHandlerService<T>
type Future = Box<Future<Item = server::Response, Error = hyper::Error>>;

fn call(&self, req: Self::Request) -> Self::Future {
let mut state = State::new();
set_request_id(&mut state, &req);

// Hyper doesn't allow us to present an affine-typed `Handler` interface directly. We have
// to emulate the promise given by hyper's documentation, by creating a `Handler` value and
// immediately consuming it.
match self.t.new_handler() {
Ok(handler) => {
handler
.handle(State::new(), req)
.handle(state, req)
.and_then(|(_, response)| future::ok(response))
.or_else(|(_, error)| future::err(error))
.boxed()
Expand Down
38 changes: 5 additions & 33 deletions src/router/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ use handler::{NewHandler, Handler, HandlerFuture};
use router::response_extender::ResponseExtender;
use router::route::Route;
use router::tree::{SegmentMapping, Tree};
use state::request_id::set_request_id;
use state::{State, StateData};
use http::{request_path, query_string};

Expand Down Expand Up @@ -96,8 +95,6 @@ impl<'n, P> Handler for Router<'n, P>
/// `Tree`, storing any path related variables in `State` and dispatching
/// appropriately to the configured `Handler`.
fn handle(self, mut state: State, req: Request) -> Box<HandlerFuture> {
set_request_id(&mut state, &req);

let uri = req.uri().clone();
self.populate_state(&mut state, &req);
let response = self.route(uri, state, req);
Expand Down Expand Up @@ -196,13 +193,12 @@ mod tests {
use std::str::FromStr;
use hyper::{Request, Method, Uri, Body};
use hyper::header::{ContentType, ContentLength};
use uuid::Uuid;

use borrow_bag;

use router::tree::TreeBuilder;
use router::response_extender::ResponseExtenderBuilder;
use state::request_id;
use state::set_request_id;

#[test]
fn executes_response_extender_when_present() {
Expand All @@ -223,7 +219,8 @@ mod tests {
let uri = Uri::from_str("https://test.gotham.rs").unwrap();
let request: Request<Body> = Request::new(method, uri);

let state = State::new();
let mut state = State::new();
set_request_id(&mut state, &request);
let result = router.handle(state, request).wait();

match result {
Expand All @@ -250,7 +247,8 @@ mod tests {
request.set_version(version.clone());
request.headers_mut().set(ContentType::json());

let state = State::new();
let mut state = State::new();
set_request_id(&mut state, &request);
let result = router.handle(state, request).wait();

match result {
Expand All @@ -268,30 +266,4 @@ mod tests {
Err(_) => panic!("Router should have correctly handled request"),
};
}

#[test]
fn populates_request_id() {
let tree_builder = TreeBuilder::new();
let tree = tree_builder.finalize();
let pipelines = borrow_bag::new_borrow_bag();
let response_extender = ResponseExtenderBuilder::new().finalize();

let router = Router::new(tree, pipelines, response_extender);
let method = Method::Get;
let uri = Uri::from_str("https://test.gotham.rs").unwrap();
let request: Request<Body> = Request::new(method, uri);

let state = State::new();
let result = router.handle(state, request).wait();

match result {
Ok((state, _res)) => {
assert_eq!(4,
Uuid::parse_str(request_id(&state))
.unwrap()
.get_version_num())
}
Err(_) => panic!("Router should have correctly handled request"),
}
}
}
1 change: 1 addition & 0 deletions src/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::collections::HashMap;
use std::any::{Any, TypeId};

pub use self::request_id::request_id;
pub use self::request_id::set_request_id;

/// Provides storage for request state, and stores one item of each type. The types used for
/// storage must implement the `gotham::state::StateData` trait to allow its storage.
Expand Down
2 changes: 1 addition & 1 deletion src/state/request_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ header! {
/// 1. If the header X-Request-ID is provided this value is used as is;
/// 2. Alternatively creates and stores a UUID v4 value.
///
/// This method MUST be invoked by Gotham, specifically by the `Router`, before handing control to
/// This method MUST be invoked by Gotham, before handing control to
/// pipelines or Handlers to ensure that a value for `RequestId` is always available.
pub fn set_request_id<'a>(state: &'a mut State, req: &Request) -> &'a str {
if !state.has::<RequestId>() {
Expand Down

0 comments on commit 3450180

Please sign in to comment.