From 3b2e2acb6c067685589a229678b603ce4c49c25b Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Mon, 12 Jul 2021 18:37:41 +0100 Subject: [PATCH] fix connection data on keep alive connections --- actix-http/src/builder.rs | 9 +--- actix-http/src/extensions.rs | 85 ++++++++++++++++++++++++++++-------- actix-http/src/lib.rs | 6 +-- src/server.rs | 6 +-- 4 files changed, 75 insertions(+), 31 deletions(-) diff --git a/actix-http/src/builder.rs b/actix-http/src/builder.rs index 4e68dc92..af5a377c 100644 --- a/actix-http/src/builder.rs +++ b/actix-http/src/builder.rs @@ -3,14 +3,7 @@ use std::{error::Error as StdError, fmt, marker::PhantomData, net, rc::Rc}; use actix_codec::Framed; use actix_service::{IntoServiceFactory, Service, ServiceFactory}; -use crate::{ - body::{AnyBody, MessageBody}, - config::{KeepAlive, ServiceConfig}, - h1::{self, ExpectHandler, H1Service, UpgradeHandler}, - h2::H2Service, - service::HttpService, - ConnectCallback, Extensions, Request, Response, -}; +use crate::{ConnectCallback, Extensions, Request, Response, body::{AnyBody, MessageBody}, config::{KeepAlive, ServiceConfig}, h1::{self, ExpectHandler, H1Service, UpgradeHandler}, h2::H2Service, service::HttpService}; /// A HTTP service builder /// diff --git a/actix-http/src/extensions.rs b/actix-http/src/extensions.rs index 5fdcefd6..1e02063e 100644 --- a/actix-http/src/extensions.rs +++ b/actix-http/src/extensions.rs @@ -1,6 +1,7 @@ use std::{ any::{Any, TypeId}, fmt, mem, + rc::Rc, }; use ahash::AHashMap; @@ -12,7 +13,7 @@ use ahash::AHashMap; pub struct Extensions { /// Use FxHasher with a std HashMap with for faster /// lookups on the small `TypeId` (u64 equivalent) keys. - map: AHashMap>, + map: AHashMap>, } impl Extensions { @@ -38,8 +39,8 @@ impl Extensions { /// ``` pub fn insert(&mut self, val: T) -> Option { self.map - .insert(TypeId::of::(), Box::new(val)) - .and_then(downcast_owned) + .insert(TypeId::of::(), Rc::new(val)) + .and_then(downcast_rc) } /// Check if map contains an item of a given type. @@ -70,19 +71,19 @@ impl Extensions { .and_then(|boxed| boxed.downcast_ref()) } - /// Get a mutable reference to an item of a given type. - /// - /// ``` - /// # use actix_http::Extensions; - /// let mut map = Extensions::new(); - /// map.insert(1u32); - /// assert_eq!(map.get_mut::(), Some(&mut 1u32)); - /// ``` - pub fn get_mut(&mut self) -> Option<&mut T> { - self.map - .get_mut(&TypeId::of::()) - .and_then(|boxed| boxed.downcast_mut()) - } + // /// Get a mutable reference to an item of a given type. + // /// + // /// ``` + // /// # use actix_http::Extensions; + // /// let mut map = Extensions::new(); + // /// map.insert(1u32); + // /// assert_eq!(map.get_mut::(), Some(&mut 1u32)); + // /// ``` + // pub fn get_mut(&mut self) -> Option<&mut T> { + // self.map + // .get_mut(&TypeId::of::()) + // .and_then(|boxed| boxed.downcast_mut()) + // } /// Remove an item from the map of a given type. /// @@ -99,7 +100,7 @@ impl Extensions { /// assert!(!map.contains::()); /// ``` pub fn remove(&mut self) -> Option { - self.map.remove(&TypeId::of::()).and_then(downcast_owned) + self.map.remove(&TypeId::of::()).and_then(downcast_rc) } /// Clear the `Extensions` of all inserted extensions. @@ -128,6 +129,13 @@ impl Extensions { pub(crate) fn drain_from(&mut self, other: &mut Self) { self.map.extend(mem::take(&mut other.map)); } + + /// Sets (or overrides) items from cloneable extensions map into this map. + pub(crate) fn clone_from(&mut self, other: &Self) { + for (k, val) in &other.map { + self.map.insert(*k, Rc::clone(val)); + } + } } impl fmt::Debug for Extensions { @@ -140,6 +148,49 @@ fn downcast_owned(boxed: Box) -> Option { boxed.downcast().ok().map(|boxed| *boxed) } +fn downcast_rc(boxed: Rc) -> Option { + boxed + .downcast() + .ok() + .and_then(|boxed| Rc::try_unwrap(boxed).ok()) +} + +// /// A type map for request extensions. +// /// +// /// All entries into this map must be owned types (or static references). +// #[derive(Default)] +// pub struct CloneableExtensions { +// /// Use FxHasher with a std HashMap with for faster +// /// lookups on the small `TypeId` (u64 equivalent) keys. +// map: AHashMap>, +// } + +// impl CloneableExtensions { +// pub(crate) fn priv_clone(&self) -> CloneableExtensions { +// Self { +// map: self.map.clone(), +// } +// } + +// /// Insert an item into the map. +// /// +// /// If an item of this type was already stored, it will be replaced and returned. +// /// +// /// ``` +// /// # use actix_http::Extensions; +// /// let mut map = Extensions::new(); +// /// assert_eq!(map.insert(""), None); +// /// assert_eq!(map.insert(1u32), None); +// /// assert_eq!(map.insert(2u32), Some(1u32)); +// /// assert_eq!(*map.get::().unwrap(), 2u32); +// /// ``` +// pub fn insert(&mut self, val: T) -> Option { +// self.map +// .insert(TypeId::of::(), Rc::new(val)) +// .and_then(downcast_rc) +// } +// } + #[cfg(test)] mod tests { use super::*; diff --git a/actix-http/src/lib.rs b/actix-http/src/lib.rs index d22e1ee4..e0a7e70a 100644 --- a/actix-http/src/lib.rs +++ b/actix-http/src/lib.rs @@ -119,7 +119,7 @@ impl OnConnectData { on_connect_ext: Option<&ConnectCallback>, ) -> Self { let ext = on_connect_ext.map(|handler| { - let mut extensions = Extensions::new(); + let mut extensions = Extensions::default(); handler(io, &mut extensions); extensions }); @@ -130,8 +130,8 @@ impl OnConnectData { /// Merge self into given request's extensions. #[inline] pub(crate) fn merge_into(&mut self, req: &mut Request) { - if let Some(ref mut ext) = self.0 { - req.head.extensions.get_mut().drain_from(ext); + if let Some(ref ext) = self.0 { + req.head.extensions.get_mut().clone_from(ext); } } } diff --git a/src/server.rs b/src/server.rs index f15183f8..194b4913 100644 --- a/src/server.rs +++ b/src/server.rs @@ -107,10 +107,10 @@ where /// It will receive a `&std::any::Any`, which contains underlying connection type and an /// [Extensions] container so that request-local data can be passed to middleware and handlers. /// - /// For example: - /// - `actix_tls::openssl::SslStream` when using openssl. + /// # Connection Types + /// - `actix_web::rt::net::TcpStream` when no TLS layer is used. /// - `actix_tls::rustls::TlsStream` when using rustls. - /// - `actix_web::rt::net::TcpStream` when no encryption is used. + /// - `actix_tls::openssl::SslStream` when using openssl. /// /// See `on_connect` example for additional details. pub fn on_connect(self, f: CB) -> HttpServer