Open
Description
Hi,
I am using axum-sessions inside a middleware layer that is checking if the user is logged in and short-circuits the router with a StatusCode::UNAUTHORIZED
response if they are not.
If I then try to use a WritableSession in a route that is "behind" this middleware layer I get a deadlock that I am guessing is caused by the internal RWLock that is being acquired while the middleware layer is still holding a reference to the ReadableSession.
For the time being I am going to work-around this issue by bypassing the middleware when I need a WritableSession but is there a way to release the ReadableSession from the middleware after I am done using it so that I can avoid this issue?
Here's a minimal POC:
Cargo.toml
[package]
name = "axum-sessions-deadlock"
version = "0.1.0"
edition = "2021"
[dependencies]
axum = "0.6"
axum-sessions = "0.5"
hyper = "0.14"
rand = "0.8"
tokio = { version = "1", features = ["full"] }
toml = "0.7"
tower-http = "0.4"
main.rs
use axum::http::Request;
use axum::middleware::Next;
use axum::response::Response;
use axum::{routing::get, Router};
use axum_sessions::extractors::{ReadableSession, WritableSession};
use axum_sessions::{async_session::MemoryStore, SessionLayer};
use hyper::StatusCode;
use rand::RngCore;
#[tokio::main]
async fn main() {
let store = MemoryStore::new();
let mut secret = [0u8; 128];
rand::thread_rng().fill_bytes(&mut secret);
let session_layer = SessionLayer::new(store, &secret).with_secure(false);
let app = Router::new()
.route("/", get(deadlock))
.layer(axum::middleware::from_fn(auth_middleware))
.layer(session_layer);
eprintln!("Listening on 127.0.0.1:3000");
axum::Server::bind(&"127.0.0.1:3000".parse().unwrap())
.serve(app.into_make_service())
.await
.unwrap();
}
pub async fn auth_middleware<T>(
session: ReadableSession,
request: Request<T>,
next: Next<T>,
) -> Result<Response, StatusCode> {
// e.g: check if user is logged in
// let login: Option<String> = session.get("login");
// match login {
// None => Err(StatusCode::UNAUTHORIZED),
// Some(_) => Ok(next.run(request).await),
// }
// assume logged-in
Ok(next.run(request).await)
}
async fn deadlock(mut session: WritableSession) -> StatusCode {
// e.g: session.destroy();
StatusCode::NO_CONTENT
}
Thanks
Metadata
Metadata
Assignees
Labels
No labels
Activity