summaryrefslogtreecommitdiffstats
path: root/fatcat-openapi/src/context.rs
diff options
context:
space:
mode:
Diffstat (limited to 'fatcat-openapi/src/context.rs')
-rw-r--r--fatcat-openapi/src/context.rs120
1 files changed, 120 insertions, 0 deletions
diff --git a/fatcat-openapi/src/context.rs b/fatcat-openapi/src/context.rs
new file mode 100644
index 0000000..d782855
--- /dev/null
+++ b/fatcat-openapi/src/context.rs
@@ -0,0 +1,120 @@
+use crate::Api;
+use futures::future::BoxFuture;
+use hyper::header::HeaderName;
+use hyper::{service::Service, Error, Request, Response, StatusCode};
+use std::default::Default;
+use std::io;
+use std::marker::PhantomData;
+use std::task::{Context, Poll};
+use swagger::auth::{AuthData, Authorization, Bearer, Scopes};
+use swagger::{EmptyContext, Has, Pop, Push, XSpanIdString};
+use url::form_urlencoded;
+
+pub struct MakeAddContext<T, A> {
+ inner: T,
+ marker: PhantomData<A>,
+}
+
+impl<T, A, B, C, D> MakeAddContext<T, A>
+where
+ A: Default + Push<XSpanIdString, Result = B>,
+ B: Push<Option<AuthData>, Result = C>,
+ C: Push<Option<Authorization>, Result = D>,
+{
+ pub fn new(inner: T) -> MakeAddContext<T, A> {
+ MakeAddContext {
+ inner,
+ marker: PhantomData,
+ }
+ }
+}
+
+// Make a service that adds context.
+impl<Target, T, A, B, C, D> Service<Target> for MakeAddContext<T, A>
+where
+ Target: Send,
+ A: Default + Push<XSpanIdString, Result = B> + Send,
+ B: Push<Option<AuthData>, Result = C>,
+ C: Push<Option<Authorization>, Result = D>,
+ D: Send + 'static,
+ T: Service<Target> + Send,
+ T::Future: Send + 'static,
+{
+ type Error = T::Error;
+ type Response = AddContext<T::Response, A, B, C, D>;
+ type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;
+
+ fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
+ self.inner.poll_ready(cx)
+ }
+
+ fn call(&mut self, target: Target) -> Self::Future {
+ let service = self.inner.call(target);
+
+ Box::pin(async move { Ok(AddContext::new(service.await?)) })
+ }
+}
+
+/// Middleware to add context data from the request
+pub struct AddContext<T, A, B, C, D>
+where
+ A: Default + Push<XSpanIdString, Result = B>,
+ B: Push<Option<AuthData>, Result = C>,
+ C: Push<Option<Authorization>, Result = D>,
+{
+ inner: T,
+ marker: PhantomData<A>,
+}
+
+impl<T, A, B, C, D> AddContext<T, A, B, C, D>
+where
+ A: Default + Push<XSpanIdString, Result = B>,
+ B: Push<Option<AuthData>, Result = C>,
+ C: Push<Option<Authorization>, Result = D>,
+{
+ pub fn new(inner: T) -> Self {
+ AddContext {
+ inner,
+ marker: PhantomData,
+ }
+ }
+}
+
+impl<T, A, B, C, D, ReqBody> Service<Request<ReqBody>> for AddContext<T, A, B, C, D>
+where
+ A: Default + Push<XSpanIdString, Result = B>,
+ B: Push<Option<AuthData>, Result = C>,
+ C: Push<Option<Authorization>, Result = D>,
+ D: Send + 'static,
+ T: Service<(Request<ReqBody>, D)>,
+{
+ type Error = T::Error;
+ type Future = T::Future;
+ type Response = T::Response;
+
+ fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
+ self.inner.poll_ready(cx)
+ }
+
+ fn call(&mut self, request: Request<ReqBody>) -> Self::Future {
+ let context = A::default().push(XSpanIdString::get_or_generate(&request));
+ let headers = request.headers();
+
+ {
+ use std::ops::Deref;
+ use swagger::auth::Basic;
+ if let Some(basic) = swagger::auth::from_headers::<Basic>(&headers) {
+ let auth_data = AuthData::Basic(basic);
+ let context = context.push(Some(auth_data));
+ let context = context.push(None::<Authorization>);
+
+ return self.inner.call((request, context));
+ }
+ }
+
+ let context = context.push(None::<AuthData>);
+ let context = context.push(None::<Authorization>);
+
+ self.inner.call((request, context))
+ }
+}