1
0
Fork 0
mirror of https://gitlab.com/msrd0/gotham-restful.git synced 2025-02-23 04:52:28 +00:00

update jsonwebtoken, futures, and hyper and co

This commit is contained in:
Dominic 2020-04-14 17:44:07 +02:00
parent fbcc626478
commit f425f21ff3
Signed by: msrd0
GPG key ID: DCC8C247452E98F9
11 changed files with 83 additions and 71 deletions

View file

@ -15,10 +15,9 @@ gitlab = { repository = "msrd0/gotham-restful", branch = "master" }
[dependencies] [dependencies]
fake = "2.2" fake = "2.2"
gotham = "0.4" gotham = { git = "https://github.com/gotham-rs/gotham", version = "0.5.0-dev", default-features = false }
gotham_derive = "0.4" gotham_derive = { git = "https://github.com/gotham-rs/gotham", version = "0.5.0-dev", default-features = false }
gotham_restful = { version = "0.0.3", features = ["auth", "openapi"] } gotham_restful = { version = "0.0.3", features = ["auth", "openapi"] }
hyper = "0.12"
log = "0.4" log = "0.4"
log4rs = { version = "0.8", features = ["console_appender"], default-features = false } log4rs = { version = "0.8", features = ["console_appender"], default-features = false }
serde = "1" serde = "1"

View file

@ -15,17 +15,19 @@ repository = "https://gitlab.com/msrd0/gotham-restful"
gitlab = { repository = "msrd0/gotham-restful", branch = "master" } gitlab = { repository = "msrd0/gotham-restful", branch = "master" }
[dependencies] [dependencies]
base64 = { version = ">=0.10.1, <0.12", optional = true } base64 = { version = "0.12.0", optional = true }
chrono = { version = "0.4.10", optional = true } chrono = { version = "0.4.10", optional = true }
cookie = { version = "0.12", optional = true } cookie = { version = "0.13.3", optional = true }
futures = "0.1.29" futures = "0.3.4"
gotham = "0.4" futures-core = "0.3.4"
gotham_derive = "0.4" futures-util = "0.3.4"
gotham_middleware_diesel = { version = "0.1", optional = true } gotham = { git = "https://github.com/gotham-rs/gotham", version = "0.5.0-dev", default-features = false }
gotham_derive = { git = "https://github.com/gotham-rs/gotham", version = "0.5.0-dev" }
gotham_middleware_diesel = { git = "https://github.com/gotham-rs/gotham", version = "0.1.0", optional = true }
gotham_restful_derive = { version = "0.0.2" } gotham_restful_derive = { version = "0.0.2" }
hyper = "0.12.35" hyper = "0.13.4"
indexmap = { version = "1.3.0", optional = true } indexmap = { version = "1.3.0", optional = true }
jsonwebtoken = { version = "6.0.1", optional = true } jsonwebtoken = { version = "7.1.0", optional = true }
log = { version = "0.4.8", optional = true } log = { version = "0.4.8", optional = true }
mime = "0.3.16" mime = "0.3.16"
openapiv3 = { version = "0.3", optional = true } openapiv3 = { version = "0.3", optional = true }
@ -34,6 +36,7 @@ serde_json = "1.0.45"
uuid = { version = ">= 0.1, < 0.9", optional = true } uuid = { version = ">= 0.1, < 0.9", optional = true }
[dev-dependencies] [dev-dependencies]
futures-executor = "0.3.4"
paste = "0.1.10" paste = "0.1.10"
thiserror = "1" thiserror = "1"

View file

@ -1,17 +1,21 @@
use crate::HeaderName; use crate::HeaderName;
use cookie::CookieJar; use cookie::CookieJar;
use futures::{future, future::Future}; use futures_util::{future, future::{FutureExt, TryFutureExt}};
use gotham::{ use gotham::{
handler::HandlerFuture, handler::HandlerFuture,
middleware::{Middleware, NewMiddleware}, middleware::{Middleware, NewMiddleware},
state::{FromState, State} state::{FromState, State}
}; };
use hyper::header::{AUTHORIZATION, HeaderMap}; use hyper::header::{AUTHORIZATION, HeaderMap};
use jsonwebtoken::errors::ErrorKind; use jsonwebtoken::{
errors::ErrorKind,
DecodingKey
};
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use std::{ use std::{
marker::PhantomData, marker::PhantomData,
panic::RefUnwindSafe panic::RefUnwindSafe,
pin::Pin
}; };
pub use jsonwebtoken::Validation as AuthValidation; pub use jsonwebtoken::Validation as AuthValidation;
@ -248,7 +252,7 @@ where
}; };
// validate the token // validate the token
let data : Data = match jsonwebtoken::decode(&token, &secret, &self.validation) { let data : Data = match jsonwebtoken::decode(&token, &DecodingKey::from_secret(&secret), &self.validation) {
Ok(data) => data.claims, Ok(data) => data.claims,
Err(e) => match dbg!(e.into_kind()) { Err(e) => match dbg!(e.into_kind()) {
ErrorKind::ExpiredSignature => return AuthStatus::Expired, ErrorKind::ExpiredSignature => return AuthStatus::Expired,
@ -266,9 +270,9 @@ where
Data : DeserializeOwned + Send + 'static, Data : DeserializeOwned + Send + 'static,
Handler : AuthHandler<Data> Handler : AuthHandler<Data>
{ {
fn call<Chain>(self, mut state : State, chain : Chain) -> Box<HandlerFuture> fn call<Chain>(self, mut state : State, chain : Chain) -> Pin<Box<HandlerFuture>>
where where
Chain : FnOnce(State) -> Box<HandlerFuture> Chain : FnOnce(State) -> Pin<Box<HandlerFuture>>
{ {
// put the source in our state, required for e.g. openapi // put the source in our state, required for e.g. openapi
state.put(self.source.clone()); state.put(self.source.clone());
@ -278,7 +282,7 @@ where
state.put(status); state.put(status);
// call the rest of the chain // call the rest of the chain
Box::new(chain(state).and_then(|(state, res)| future::ok((state, res)))) chain(state).and_then(|(state, res)| future::ok((state, res))).boxed()
} }
} }

View file

@ -105,7 +105,7 @@ extern crate self as gotham_restful;
#[macro_use] extern crate serde; #[macro_use] extern crate serde;
#[doc(no_inline)] #[doc(no_inline)]
pub use hyper::{header::HeaderName, Chunk, StatusCode}; pub use gotham::hyper::{header::HeaderName, StatusCode};
#[doc(no_inline)] #[doc(no_inline)]
pub use mime::Mime; pub use mime::Mime;
@ -115,8 +115,10 @@ pub use gotham_restful_derive::*;
#[doc(hidden)] #[doc(hidden)]
pub mod export pub mod export
{ {
pub use futures::future::Future; pub use gotham::{
pub use gotham::state::{FromState, State}; hyper::body::Bytes,
state::{FromState, State}
};
#[cfg(feature = "database")] #[cfg(feature = "database")]
pub use gotham_middleware_diesel::Repo; pub use gotham_middleware_diesel::Repo;

View file

@ -6,7 +6,7 @@ use crate::{
OpenapiType, OpenapiType,
RequestBody RequestBody
}; };
use futures::future::ok; use futures_util::{future, future::FutureExt};
use gotham::{ use gotham::{
handler::{Handler, HandlerFuture, NewHandler}, handler::{Handler, HandlerFuture, NewHandler},
helpers::http::response::create_response, helpers::http::response::create_response,
@ -22,7 +22,10 @@ use openapiv3::{
ReferenceOr, ReferenceOr::Item, ReferenceOr::Reference, RequestBody as OARequestBody, Response, Responses, Schema, ReferenceOr, ReferenceOr::Item, ReferenceOr::Reference, RequestBody as OARequestBody, Response, Responses, Schema,
SchemaKind, SecurityScheme, Server, StatusCode, Type SchemaKind, SecurityScheme, Server, StatusCode, Type
}; };
use std::panic::RefUnwindSafe; use std::{
panic::RefUnwindSafe,
pin::Pin
};
/** /**
This type is required to build routes while adding them to the generated OpenAPI Spec at the This type is required to build routes while adding them to the generated OpenAPI Spec at the
@ -175,7 +178,7 @@ fn get_security(state : &mut State) -> (Vec<SecurityRequirement>, IndexMap<Strin
impl Handler for OpenapiHandler impl Handler for OpenapiHandler
{ {
fn handle(self, mut state : State) -> Box<HandlerFuture> fn handle(self, mut state : State) -> Pin<Box<HandlerFuture>>
{ {
let mut openapi = self.0; let mut openapi = self.0;
let security_schemes = get_security(&mut state); let security_schemes = get_security(&mut state);
@ -186,12 +189,12 @@ impl Handler for OpenapiHandler
match serde_json::to_string(&openapi) { match serde_json::to_string(&openapi) {
Ok(body) => { Ok(body) => {
let res = create_response(&state, hyper::StatusCode::OK, APPLICATION_JSON, body); let res = create_response(&state, hyper::StatusCode::OK, APPLICATION_JSON, body);
Box::new(ok((state, res))) future::ok((state, res)).boxed()
}, },
Err(e) => { Err(e) => {
error!("Unable to handle OpenAPI request due to error: {}", e); error!("Unable to handle OpenAPI request due to error: {}", e);
let res = create_response(&state, hyper::StatusCode::INTERNAL_SERVER_ERROR, TEXT_PLAIN, ""); let res = create_response(&state, hyper::StatusCode::INTERNAL_SERVER_ERROR, TEXT_PLAIN, "");
Box::new(ok((state, res))) future::ok((state, res)).boxed()
} }
} }
} }

View file

@ -1,7 +1,7 @@
use crate::{ResponseBody, StatusCode}; use crate::{ResponseBody, StatusCode};
#[cfg(feature = "openapi")] #[cfg(feature = "openapi")]
use crate::{OpenapiSchema, OpenapiType}; use crate::{OpenapiSchema, OpenapiType};
use hyper::Body; use gotham::hyper::Body;
#[cfg(feature = "errorlog")] #[cfg(feature = "errorlog")]
use log::error; use log::error;
use mime::{Mime, APPLICATION_JSON, STAR_STAR}; use mime::{Mime, APPLICATION_JSON, STAR_STAR};
@ -65,12 +65,13 @@ impl Response
} }
#[cfg(test)] #[cfg(test)]
fn full_body(self) -> Vec<u8> fn full_body(mut self) -> Result<Vec<u8>, <Body as gotham::hyper::body::HttpBody>::Error>
{ {
use futures::{future::Future, stream::Stream}; use futures_executor::block_on;
use gotham::hyper::body::to_bytes;
let bytes : &[u8] = &self.body.concat2().wait().unwrap().into_bytes(); let bytes : &[u8] = &block_on(to_bytes(&mut self.body))?;
bytes.to_vec() Ok(bytes.to_vec())
} }
} }
@ -532,7 +533,7 @@ mod test
let res = ok.into_response().expect("didn't expect error response"); let res = ok.into_response().expect("didn't expect error response");
assert_eq!(res.status, StatusCode::OK); assert_eq!(res.status, StatusCode::OK);
assert_eq!(res.mime, Some(APPLICATION_JSON)); assert_eq!(res.mime, Some(APPLICATION_JSON));
assert_eq!(res.full_body(), r#"{"msg":""}"#.as_bytes()); assert_eq!(res.full_body().unwrap(), r#"{"msg":""}"#.as_bytes());
} }
#[test] #[test]
@ -542,7 +543,7 @@ mod test
let res = err.into_response().expect("didn't expect error response"); let res = err.into_response().expect("didn't expect error response");
assert_eq!(res.status, StatusCode::INTERNAL_SERVER_ERROR); assert_eq!(res.status, StatusCode::INTERNAL_SERVER_ERROR);
assert_eq!(res.mime, Some(APPLICATION_JSON)); assert_eq!(res.mime, Some(APPLICATION_JSON));
assert_eq!(res.full_body(), format!(r#"{{"error":true,"message":"{}"}}"#, MsgError::default()).as_bytes()); assert_eq!(res.full_body().unwrap(), format!(r#"{{"error":true,"message":"{}"}}"#, MsgError::default()).as_bytes());
} }
#[test] #[test]
@ -552,7 +553,7 @@ mod test
let res = success.into_response().expect("didn't expect error response"); let res = success.into_response().expect("didn't expect error response");
assert_eq!(res.status, StatusCode::OK); assert_eq!(res.status, StatusCode::OK);
assert_eq!(res.mime, Some(APPLICATION_JSON)); assert_eq!(res.mime, Some(APPLICATION_JSON));
assert_eq!(res.full_body(), r#"{"msg":""}"#.as_bytes()); assert_eq!(res.full_body().unwrap(), r#"{"msg":""}"#.as_bytes());
} }
#[test] #[test]
@ -562,7 +563,7 @@ mod test
let res = no_content.into_response().expect("didn't expect error response"); let res = no_content.into_response().expect("didn't expect error response");
assert_eq!(res.status, StatusCode::NO_CONTENT); assert_eq!(res.status, StatusCode::NO_CONTENT);
assert_eq!(res.mime, None); assert_eq!(res.mime, None);
assert_eq!(res.full_body(), &[] as &[u8]); assert_eq!(res.full_body().unwrap(), &[] as &[u8]);
} }
#[test] #[test]
@ -572,7 +573,7 @@ mod test
let res = no_content.into_response().expect("didn't expect error response"); let res = no_content.into_response().expect("didn't expect error response");
assert_eq!(res.status, StatusCode::NO_CONTENT); assert_eq!(res.status, StatusCode::NO_CONTENT);
assert_eq!(res.mime, None); assert_eq!(res.mime, None);
assert_eq!(res.full_body(), &[] as &[u8]); assert_eq!(res.full_body().unwrap(), &[] as &[u8]);
} }
#[test] #[test]
@ -583,6 +584,6 @@ mod test
let res = raw.into_response().expect("didn't expect error response"); let res = raw.into_response().expect("didn't expect error response");
assert_eq!(res.status, StatusCode::OK); assert_eq!(res.status, StatusCode::OK);
assert_eq!(res.mime, Some(TEXT_PLAIN)); assert_eq!(res.mime, Some(TEXT_PLAIN));
assert_eq!(res.full_body(), msg.as_bytes()); assert_eq!(res.full_body().unwrap(), msg.as_bytes());
} }
} }

View file

@ -7,12 +7,9 @@ use crate::{
#[cfg(feature = "openapi")] #[cfg(feature = "openapi")]
use crate::OpenapiRouter; use crate::OpenapiRouter;
use futures::{ use futures_util::{future, future::FutureExt};
future::{Future, err, ok},
stream::Stream
};
use gotham::{ use gotham::{
handler::{HandlerFuture, IntoHandlerError}, handler::{HandlerFuture, IntoHandlerError, IntoHandlerFuture},
helpers::http::response::{create_empty_response, create_response}, helpers::http::response::{create_empty_response, create_response},
pipeline::chain::PipelineHandleChain, pipeline::chain::PipelineHandleChain,
router::{ router::{
@ -26,14 +23,18 @@ use gotham::{
}, },
state::{FromState, State} state::{FromState, State}
}; };
use hyper::{ use gotham::hyper::{
body::to_bytes,
header::CONTENT_TYPE, header::CONTENT_TYPE,
Body, Body,
HeaderMap, HeaderMap,
Method Method
}; };
use mime::{Mime, APPLICATION_JSON}; use mime::{Mime, APPLICATION_JSON};
use std::panic::RefUnwindSafe; use std::{
panic::RefUnwindSafe,
pin::Pin
};
/// Allow us to extract an id from a path. /// Allow us to extract an id from a path.
#[derive(Deserialize, StateData, StaticResponseExtender)] #[derive(Deserialize, StateData, StaticResponseExtender)]
@ -88,7 +89,7 @@ fn response_from(res : Response, state : &State) -> hyper::Response<Body>
r r
} }
fn to_handler_future<F, R>(mut state : State, get_result : F) -> Box<HandlerFuture> fn to_handler_future<F, R>(mut state : State, get_result : F) -> Pin<Box<HandlerFuture>>
where where
F : FnOnce(&mut State) -> R, F : FnOnce(&mut State) -> R,
R : ResourceResult R : ResourceResult
@ -97,32 +98,31 @@ where
match res { match res {
Ok(res) => { Ok(res) => {
let r = response_from(res, &state); let r = response_from(res, &state);
Box::new(ok((state, r))) (state, r).into_handler_future()
}, },
Err(e) => Box::new(err((state, e.into_handler_error()))) Err(e) => future::err((state, e.into_handler_error())).boxed()
} }
} }
fn handle_with_body<Body, F, R>(mut state : State, get_result : F) -> Box<HandlerFuture> fn handle_with_body<Body, F, R>(mut state : State, get_result : F) -> Pin<Box<HandlerFuture>>
where where
Body : RequestBody, Body : RequestBody,
F : FnOnce(&mut State, Body) -> R + Send + 'static, F : FnOnce(&mut State, Body) -> R + Send + 'static,
R : ResourceResult R : ResourceResult
{ {
let f = hyper::Body::take_from(&mut state) let f = to_bytes(gotham::hyper::Body::take_from(&mut state))
.concat2()
.then(|body| { .then(|body| {
let body = match body { let body = match body {
Ok(body) => body, Ok(body) => body,
Err(e) => return err((state, e.into_handler_error())) Err(e) => return future::err((state, e.into_handler_error()))
}; };
let content_type : Mime = match HeaderMap::borrow_from(&state).get(CONTENT_TYPE) { let content_type : Mime = match HeaderMap::borrow_from(&state).get(CONTENT_TYPE) {
Some(content_type) => content_type.to_str().unwrap().parse().unwrap(), Some(content_type) => content_type.to_str().unwrap().parse().unwrap(),
None => { None => {
let res = create_empty_response(&state, StatusCode::UNSUPPORTED_MEDIA_TYPE); let res = create_empty_response(&state, StatusCode::UNSUPPORTED_MEDIA_TYPE);
return ok((state, res)) return future::ok((state, res))
} }
}; };
@ -133,9 +133,9 @@ where
match serde_json::to_string(&error) { match serde_json::to_string(&error) {
Ok(json) => { Ok(json) => {
let res = create_response(&state, StatusCode::BAD_REQUEST, APPLICATION_JSON, json); let res = create_response(&state, StatusCode::BAD_REQUEST, APPLICATION_JSON, json);
ok((state, res)) future::ok((state, res))
}, },
Err(e) => err((state, e.into_handler_error())) Err(e) => future::err((state, e.into_handler_error()))
} }
} }
}; };
@ -144,22 +144,22 @@ where
match res { match res {
Ok(res) => { Ok(res) => {
let r = response_from(res, &state); let r = response_from(res, &state);
ok((state, r)) future::ok((state, r))
}, },
Err(e) => err((state, e.into_handler_error())) Err(e) => future::err((state, e.into_handler_error()))
} }
}); });
Box::new(f) f.boxed()
} }
fn read_all_handler<Handler : ResourceReadAll>(state : State) -> Box<HandlerFuture> fn read_all_handler<Handler : ResourceReadAll>(state : State) -> Pin<Box<HandlerFuture>>
{ {
to_handler_future(state, |state| Handler::read_all(state)) to_handler_future(state, |state| Handler::read_all(state))
} }
fn read_handler<Handler : ResourceRead>(state : State) -> Box<HandlerFuture> fn read_handler<Handler : ResourceRead>(state : State) -> Pin<Box<HandlerFuture>>
{ {
let id = { let id = {
let path : &PathExtractor<Handler::ID> = PathExtractor::borrow_from(&state); let path : &PathExtractor<Handler::ID> = PathExtractor::borrow_from(&state);
@ -168,23 +168,23 @@ fn read_handler<Handler : ResourceRead>(state : State) -> Box<HandlerFuture>
to_handler_future(state, |state| Handler::read(state, id)) to_handler_future(state, |state| Handler::read(state, id))
} }
fn search_handler<Handler : ResourceSearch>(mut state : State) -> Box<HandlerFuture> fn search_handler<Handler : ResourceSearch>(mut state : State) -> Pin<Box<HandlerFuture>>
{ {
let query = Handler::Query::take_from(&mut state); let query = Handler::Query::take_from(&mut state);
to_handler_future(state, |state| Handler::search(state, query)) to_handler_future(state, |state| Handler::search(state, query))
} }
fn create_handler<Handler : ResourceCreate>(state : State) -> Box<HandlerFuture> fn create_handler<Handler : ResourceCreate>(state : State) -> Pin<Box<HandlerFuture>>
{ {
handle_with_body::<Handler::Body, _, _>(state, |state, body| Handler::create(state, body)) handle_with_body::<Handler::Body, _, _>(state, |state, body| Handler::create(state, body))
} }
fn update_all_handler<Handler : ResourceUpdateAll>(state : State) -> Box<HandlerFuture> fn update_all_handler<Handler : ResourceUpdateAll>(state : State) -> Pin<Box<HandlerFuture>>
{ {
handle_with_body::<Handler::Body, _, _>(state, |state, body| Handler::update_all(state, body)) handle_with_body::<Handler::Body, _, _>(state, |state, body| Handler::update_all(state, body))
} }
fn update_handler<Handler : ResourceUpdate>(state : State) -> Box<HandlerFuture> fn update_handler<Handler : ResourceUpdate>(state : State) -> Pin<Box<HandlerFuture>>
{ {
let id = { let id = {
let path : &PathExtractor<Handler::ID> = PathExtractor::borrow_from(&state); let path : &PathExtractor<Handler::ID> = PathExtractor::borrow_from(&state);
@ -193,12 +193,12 @@ fn update_handler<Handler : ResourceUpdate>(state : State) -> Box<HandlerFuture>
handle_with_body::<Handler::Body, _, _>(state, |state, body| Handler::update(state, id, body)) handle_with_body::<Handler::Body, _, _>(state, |state, body| Handler::update(state, id, body))
} }
fn delete_all_handler<Handler : ResourceDeleteAll>(state : State) -> Box<HandlerFuture> fn delete_all_handler<Handler : ResourceDeleteAll>(state : State) -> Pin<Box<HandlerFuture>>
{ {
to_handler_future(state, |state| Handler::delete_all(state)) to_handler_future(state, |state| Handler::delete_all(state))
} }
fn delete_handler<Handler : ResourceDelete>(state : State) -> Box<HandlerFuture> fn delete_handler<Handler : ResourceDelete>(state : State) -> Pin<Box<HandlerFuture>>
{ {
let id = { let id = {
let path : &PathExtractor<Handler::ID> = PathExtractor::borrow_from(&state); let path : &PathExtractor<Handler::ID> = PathExtractor::borrow_from(&state);

View file

@ -2,7 +2,7 @@
use crate::OpenapiType; use crate::OpenapiType;
use crate::result::ResourceError; use crate::result::ResourceError;
use hyper::Chunk; use gotham::hyper::body::Bytes;
use mime::{Mime, APPLICATION_JSON}; use mime::{Mime, APPLICATION_JSON};
use serde::{de::DeserializeOwned, Serialize}; use serde::{de::DeserializeOwned, Serialize};
@ -46,14 +46,14 @@ pub trait FromBody : Sized
type Err : Into<ResourceError>; type Err : Into<ResourceError>;
/// Create the request body from a raw body and the content type. /// Create the request body from a raw body and the content type.
fn from_body(body : Chunk, content_type : Mime) -> Result<Self, Self::Err>; fn from_body(body : Bytes, content_type : Mime) -> Result<Self, Self::Err>;
} }
impl<T : DeserializeOwned> FromBody for T impl<T : DeserializeOwned> FromBody for T
{ {
type Err = serde_json::Error; type Err = serde_json::Error;
fn from_body(body : Chunk, _content_type : Mime) -> Result<Self, Self::Err> fn from_body(body : Bytes, _content_type : Mime) -> Result<Self, Self::Err>
{ {
serde_json::from_slice(&body) serde_json::from_slice(&body)
} }

View file

@ -58,7 +58,7 @@ fn expand(tokens : TokenStream) -> Result<TokenStream2, Error>
{ {
type Err = String; type Err = String;
fn from_body(body : #krate::Chunk, _content_type : #krate::Mime) -> Result<Self, Self::Err> fn from_body(body : #krate::export::Bytes, _content_type : #krate::Mime) -> Result<Self, Self::Err>
{ {
let body : &[u8] = &body; let body : &[u8] = &body;
Ok(#body) Ok(#body)

View file

@ -435,7 +435,7 @@ fn expand(method : Method, attrs : TokenStream, item : TokenStream) -> Result<To
fn #method_ident(#(#args_def),*) -> #ret fn #method_ident(#(#args_def),*) -> #ret
{ {
#[allow(unused_imports)] #[allow(unused_imports)]
use #krate::export::{Future, FromState}; use #krate::export::FromState;
#block #block
} }