From 27a894cab7ab8785160090f0d0898d00e81eedd3 Mon Sep 17 00:00:00 2001 From: svartalf Date: Sat, 8 Jun 2019 00:20:55 +0300 Subject: [PATCH] Fixing the middleware multiple calls panic --- Cargo.toml | 5 +++-- README.md | 2 +- examples/middleware.rs | 27 +++++++++++++++++++++++++++ src/middleware.rs | 35 +++++++++++++++++++---------------- src/utils.rs | 26 +++++++++++--------------- 5 files changed, 61 insertions(+), 34 deletions(-) create mode 100644 examples/middleware.rs diff --git a/Cargo.toml b/Cargo.toml index 0e9ee8a07..1f48b6bfc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-web-httpauth" -version = "0.3.0" +version = "0.3.1" authors = ["svartalf "] description = "HTTP authentication schemes for actix-web" readme = "README.md" @@ -15,8 +15,9 @@ edition = "2018" [dependencies] actix-web = { version = "^1.0", default_features = false } -futures = "0.1" actix-service = "0.4.0" +futures = "0.1" +futures-locks = "0.3.3" bytes = "0.4" base64 = "0.10" diff --git a/README.md b/README.md index 51a82e39d..5e5b76d30 100644 --- a/README.md +++ b/README.md @@ -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://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) ![Apache 2.0 OR MIT licensed](https://img.shields.io/badge/license-Apache2.0%2FMIT-blue.svg) diff --git a/examples/middleware.rs b/examples/middleware.rs new file mode 100644 index 000000000..468d69de9 --- /dev/null +++ b/examples/middleware.rs @@ -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 { + 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() +} diff --git a/src/middleware.rs b/src/middleware.rs index e35efdb30..f03f26497 100644 --- a/src/middleware.rs +++ b/src/middleware.rs @@ -1,13 +1,14 @@ //! HTTP Authentication middleware. use std::marker::PhantomData; -use std::rc::Rc; +use std::sync::Arc; use actix_service::{Service, Transform}; use actix_web::dev::{ServiceRequest, ServiceResponse}; use actix_web::Error; use futures::future::{self, FutureResult}; use futures::{Async, Future, IntoFuture, Poll}; +use futures_locks::Mutex; use crate::extractors::{basic, bearer, AuthExtractor}; @@ -21,11 +22,12 @@ use crate::extractors::{basic, bearer, AuthExtractor}; /// the parsed credentials into it. /// In case of successful validation `F` callback /// is required to return the `ServiceRequest` back. +#[derive(Debug, Clone)] pub struct HttpAuthentication where T: AuthExtractor, { - process_fn: Rc, + process_fn: Arc, _extractor: PhantomData, } @@ -40,7 +42,7 @@ where /// validation callback `F`. pub fn with_fn(process_fn: F) -> HttpAuthentication { HttpAuthentication { - process_fn: Rc::new(process_fn), + process_fn: Arc::new(process_fn), _extractor: PhantomData, } } @@ -69,7 +71,7 @@ where /// // or to do something else in a async manner. /// fn validator( /// req: ServiceRequest, - /// credentials: BasicAuth, + /// credentials: BasicAuth, /// ) -> FutureResult { /// // All users are great and more than welcome! /// future::ok(req) @@ -140,7 +142,7 @@ where fn new_transform(&self, service: S) -> Self::Future { future::ok(AuthenticationMiddleware { - service: Some(service), + service: Mutex::new(service), process_fn: self.process_fn.clone(), _extractor: PhantomData, }) @@ -152,8 +154,8 @@ pub struct AuthenticationMiddleware where T: AuthExtractor, { - service: Option, - process_fn: Rc, + service: Mutex, + process_fn: Arc, _extractor: PhantomData, } @@ -176,23 +178,24 @@ where fn poll_ready(&mut self) -> Poll<(), Self::Error> { self.service - .as_mut() + .try_lock() .expect("AuthenticationMiddleware was called already") .poll_ready() } fn call(&mut self, req: Self::Request) -> Self::Future { let process_fn = self.process_fn.clone(); - let mut service = self - .service - .take() - .expect("AuthenticationMiddleware was called twice"); + // Note: cloning the mutex, not the service itself + let inner = self.service.clone(); let f = Extract::new(req) - .and_then(move |(req, credentials)| { - (process_fn)(req, credentials) - }) - .and_then(move |req| service.call(req)); + .and_then(move |(req, credentials)| (process_fn)(req, credentials)) + .and_then(move |req| { + inner + .lock() + .map_err(Into::into) + .and_then(|mut service| service.call(req)) + }); Box::new(f) } diff --git a/src/utils.rs b/src/utils.rs index 4312663e1..2b5c6ac31 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -26,24 +26,20 @@ impl<'a> Iterator for Quoted<'a> { fn next(&mut self) -> Option { match self.state { - State::YieldStr => { - match self.inner.next() { - Some(s) => { - self.state = State::YieldQuote; - Some(s) - }, - None => None, + State::YieldStr => match self.inner.next() { + Some(s) => { + self.state = State::YieldQuote; + Some(s) } + None => None, }, - State::YieldQuote => { - match self.inner.peek() { - Some(_) => { - self.state = State::YieldStr; - Some("\\\"") - }, - None => None, + State::YieldQuote => match self.inner.peek() { + Some(_) => { + self.state = State::YieldStr; + Some("\\\"") } - } + None => None, + }, } } }