1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-27 17:22:57 +01:00

Fixing the middleware multiple calls panic

This commit is contained in:
svartalf 2019-06-08 00:20:55 +03:00
parent 0ebfd790fc
commit 27a894cab7
5 changed files with 61 additions and 34 deletions

View File

@ -1,6 +1,6 @@
[package] [package]
name = "actix-web-httpauth" name = "actix-web-httpauth"
version = "0.3.0" version = "0.3.1"
authors = ["svartalf <self@svartalf.info>"] authors = ["svartalf <self@svartalf.info>"]
description = "HTTP authentication schemes for actix-web" description = "HTTP authentication schemes for actix-web"
readme = "README.md" readme = "README.md"
@ -15,8 +15,9 @@ edition = "2018"
[dependencies] [dependencies]
actix-web = { version = "^1.0", default_features = false } actix-web = { version = "^1.0", default_features = false }
futures = "0.1"
actix-service = "0.4.0" actix-service = "0.4.0"
futures = "0.1"
futures-locks = "0.3.3"
bytes = "0.4" bytes = "0.4"
base64 = "0.10" base64 = "0.10"

View File

@ -2,7 +2,7 @@
[![Latest Version](https://img.shields.io/crates/v/actix-web-httpauth.svg)](https://crates.io/crates/actix-web-httpauth) [![Latest Version](https://img.shields.io/crates/v/actix-web-httpauth.svg)](https://crates.io/crates/actix-web-httpauth)
[![Latest Version](https://docs.rs/actix-web-httpauth/badge.svg)](https://docs.rs/actix-web-httpauth) [![Latest Version](https://docs.rs/actix-web-httpauth/badge.svg)](https://docs.rs/actix-web-httpauth)
[![dependency status](https://deps.rs/crate/actix-web-httpauth/0.3.0/status.svg)](https://deps.rs/crate/actix-web-httpauth/0.3.0) [![dependency status](https://deps.rs/crate/actix-web-httpauth/0.3.1/status.svg)](https://deps.rs/crate/actix-web-httpauth/0.3.1)
![Build Status](https://travis-ci.org/svartalf/actix-web-httpauth.svg?branch=master) ![Build Status](https://travis-ci.org/svartalf/actix-web-httpauth.svg?branch=master)
![Apache 2.0 OR MIT licensed](https://img.shields.io/badge/license-Apache2.0%2FMIT-blue.svg) ![Apache 2.0 OR MIT licensed](https://img.shields.io/badge/license-Apache2.0%2FMIT-blue.svg)

27
examples/middleware.rs Normal file
View File

@ -0,0 +1,27 @@
use actix_web::dev::ServiceRequest;
use actix_web::{middleware, web, App, Error, HttpServer};
use futures::future;
use actix_web_httpauth::extractors::basic::BasicAuth;
use actix_web_httpauth::middleware::HttpAuthentication;
fn validator(
req: ServiceRequest,
_credentials: BasicAuth,
) -> future::FutureResult<ServiceRequest, Error> {
future::ok(req)
}
fn main() -> std::io::Result<()> {
HttpServer::new(|| {
let auth = HttpAuthentication::basic(validator);
App::new()
.wrap(middleware::Logger::default())
.wrap(auth)
.service(web::resource("/").to(|| "Test\r\n"))
})
.bind("127.0.0.1:8080")?
.workers(1)
.run()
}

View File

@ -1,13 +1,14 @@
//! HTTP Authentication middleware. //! HTTP Authentication middleware.
use std::marker::PhantomData; use std::marker::PhantomData;
use std::rc::Rc; use std::sync::Arc;
use actix_service::{Service, Transform}; use actix_service::{Service, Transform};
use actix_web::dev::{ServiceRequest, ServiceResponse}; use actix_web::dev::{ServiceRequest, ServiceResponse};
use actix_web::Error; use actix_web::Error;
use futures::future::{self, FutureResult}; use futures::future::{self, FutureResult};
use futures::{Async, Future, IntoFuture, Poll}; use futures::{Async, Future, IntoFuture, Poll};
use futures_locks::Mutex;
use crate::extractors::{basic, bearer, AuthExtractor}; use crate::extractors::{basic, bearer, AuthExtractor};
@ -21,11 +22,12 @@ use crate::extractors::{basic, bearer, AuthExtractor};
/// the parsed credentials into it. /// the parsed credentials into it.
/// In case of successful validation `F` callback /// In case of successful validation `F` callback
/// is required to return the `ServiceRequest` back. /// is required to return the `ServiceRequest` back.
#[derive(Debug, Clone)]
pub struct HttpAuthentication<T, F> pub struct HttpAuthentication<T, F>
where where
T: AuthExtractor, T: AuthExtractor,
{ {
process_fn: Rc<F>, process_fn: Arc<F>,
_extractor: PhantomData<T>, _extractor: PhantomData<T>,
} }
@ -40,7 +42,7 @@ where
/// validation callback `F`. /// validation callback `F`.
pub fn with_fn(process_fn: F) -> HttpAuthentication<T, F> { pub fn with_fn(process_fn: F) -> HttpAuthentication<T, F> {
HttpAuthentication { HttpAuthentication {
process_fn: Rc::new(process_fn), process_fn: Arc::new(process_fn),
_extractor: PhantomData, _extractor: PhantomData,
} }
} }
@ -69,7 +71,7 @@ where
/// // or to do something else in a async manner. /// // or to do something else in a async manner.
/// fn validator( /// fn validator(
/// req: ServiceRequest, /// req: ServiceRequest,
/// credentials: BasicAuth, /// credentials: BasicAuth,
/// ) -> FutureResult<ServiceRequest, Error> { /// ) -> FutureResult<ServiceRequest, Error> {
/// // All users are great and more than welcome! /// // All users are great and more than welcome!
/// future::ok(req) /// future::ok(req)
@ -140,7 +142,7 @@ where
fn new_transform(&self, service: S) -> Self::Future { fn new_transform(&self, service: S) -> Self::Future {
future::ok(AuthenticationMiddleware { future::ok(AuthenticationMiddleware {
service: Some(service), service: Mutex::new(service),
process_fn: self.process_fn.clone(), process_fn: self.process_fn.clone(),
_extractor: PhantomData, _extractor: PhantomData,
}) })
@ -152,8 +154,8 @@ pub struct AuthenticationMiddleware<S, F, T>
where where
T: AuthExtractor, T: AuthExtractor,
{ {
service: Option<S>, service: Mutex<S>,
process_fn: Rc<F>, process_fn: Arc<F>,
_extractor: PhantomData<T>, _extractor: PhantomData<T>,
} }
@ -176,23 +178,24 @@ where
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(&mut self) -> Poll<(), Self::Error> {
self.service self.service
.as_mut() .try_lock()
.expect("AuthenticationMiddleware was called already") .expect("AuthenticationMiddleware was called already")
.poll_ready() .poll_ready()
} }
fn call(&mut self, req: Self::Request) -> Self::Future { fn call(&mut self, req: Self::Request) -> Self::Future {
let process_fn = self.process_fn.clone(); let process_fn = self.process_fn.clone();
let mut service = self // Note: cloning the mutex, not the service itself
.service let inner = self.service.clone();
.take()
.expect("AuthenticationMiddleware was called twice");
let f = Extract::new(req) let f = Extract::new(req)
.and_then(move |(req, credentials)| { .and_then(move |(req, credentials)| (process_fn)(req, credentials))
(process_fn)(req, credentials) .and_then(move |req| {
}) inner
.and_then(move |req| service.call(req)); .lock()
.map_err(Into::into)
.and_then(|mut service| service.call(req))
});
Box::new(f) Box::new(f)
} }

View File

@ -26,24 +26,20 @@ impl<'a> Iterator for Quoted<'a> {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
match self.state { match self.state {
State::YieldStr => { State::YieldStr => match self.inner.next() {
match self.inner.next() { Some(s) => {
Some(s) => { self.state = State::YieldQuote;
self.state = State::YieldQuote; Some(s)
Some(s)
},
None => None,
} }
None => None,
}, },
State::YieldQuote => { State::YieldQuote => match self.inner.peek() {
match self.inner.peek() { Some(_) => {
Some(_) => { self.state = State::YieldStr;
self.state = State::YieldStr; Some("\\\"")
Some("\\\"")
},
None => None,
} }
} None => None,
},
} }
} }
} }