mirror of
https://github.com/actix/actix-web.git
synced 2024-12-18 06:06:36 +00:00
fix connection data on keep alive connections
This commit is contained in:
parent
293c52c3ef
commit
3b2e2acb6c
4 changed files with 75 additions and 31 deletions
|
@ -3,14 +3,7 @@ use std::{error::Error as StdError, fmt, marker::PhantomData, net, rc::Rc};
|
||||||
use actix_codec::Framed;
|
use actix_codec::Framed;
|
||||||
use actix_service::{IntoServiceFactory, Service, ServiceFactory};
|
use actix_service::{IntoServiceFactory, Service, ServiceFactory};
|
||||||
|
|
||||||
use crate::{
|
use crate::{ConnectCallback, Extensions, Request, Response, body::{AnyBody, MessageBody}, config::{KeepAlive, ServiceConfig}, h1::{self, ExpectHandler, H1Service, UpgradeHandler}, h2::H2Service, service::HttpService};
|
||||||
body::{AnyBody, MessageBody},
|
|
||||||
config::{KeepAlive, ServiceConfig},
|
|
||||||
h1::{self, ExpectHandler, H1Service, UpgradeHandler},
|
|
||||||
h2::H2Service,
|
|
||||||
service::HttpService,
|
|
||||||
ConnectCallback, Extensions, Request, Response,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A HTTP service builder
|
/// A HTTP service builder
|
||||||
///
|
///
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use std::{
|
use std::{
|
||||||
any::{Any, TypeId},
|
any::{Any, TypeId},
|
||||||
fmt, mem,
|
fmt, mem,
|
||||||
|
rc::Rc,
|
||||||
};
|
};
|
||||||
|
|
||||||
use ahash::AHashMap;
|
use ahash::AHashMap;
|
||||||
|
@ -12,7 +13,7 @@ use ahash::AHashMap;
|
||||||
pub struct Extensions {
|
pub struct Extensions {
|
||||||
/// Use FxHasher with a std HashMap with for faster
|
/// Use FxHasher with a std HashMap with for faster
|
||||||
/// lookups on the small `TypeId` (u64 equivalent) keys.
|
/// lookups on the small `TypeId` (u64 equivalent) keys.
|
||||||
map: AHashMap<TypeId, Box<dyn Any>>,
|
map: AHashMap<TypeId, Rc<dyn Any>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Extensions {
|
impl Extensions {
|
||||||
|
@ -38,8 +39,8 @@ impl Extensions {
|
||||||
/// ```
|
/// ```
|
||||||
pub fn insert<T: 'static>(&mut self, val: T) -> Option<T> {
|
pub fn insert<T: 'static>(&mut self, val: T) -> Option<T> {
|
||||||
self.map
|
self.map
|
||||||
.insert(TypeId::of::<T>(), Box::new(val))
|
.insert(TypeId::of::<T>(), Rc::new(val))
|
||||||
.and_then(downcast_owned)
|
.and_then(downcast_rc)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if map contains an item of a given type.
|
/// Check if map contains an item of a given type.
|
||||||
|
@ -70,19 +71,19 @@ impl Extensions {
|
||||||
.and_then(|boxed| boxed.downcast_ref())
|
.and_then(|boxed| boxed.downcast_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a mutable reference to an item of a given type.
|
// /// Get a mutable reference to an item of a given type.
|
||||||
///
|
// ///
|
||||||
/// ```
|
// /// ```
|
||||||
/// # use actix_http::Extensions;
|
// /// # use actix_http::Extensions;
|
||||||
/// let mut map = Extensions::new();
|
// /// let mut map = Extensions::new();
|
||||||
/// map.insert(1u32);
|
// /// map.insert(1u32);
|
||||||
/// assert_eq!(map.get_mut::<u32>(), Some(&mut 1u32));
|
// /// assert_eq!(map.get_mut::<u32>(), Some(&mut 1u32));
|
||||||
/// ```
|
// /// ```
|
||||||
pub fn get_mut<T: 'static>(&mut self) -> Option<&mut T> {
|
// pub fn get_mut<T: 'static>(&mut self) -> Option<&mut T> {
|
||||||
self.map
|
// self.map
|
||||||
.get_mut(&TypeId::of::<T>())
|
// .get_mut(&TypeId::of::<T>())
|
||||||
.and_then(|boxed| boxed.downcast_mut())
|
// .and_then(|boxed| boxed.downcast_mut())
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// Remove an item from the map of a given type.
|
/// Remove an item from the map of a given type.
|
||||||
///
|
///
|
||||||
|
@ -99,7 +100,7 @@ impl Extensions {
|
||||||
/// assert!(!map.contains::<u32>());
|
/// assert!(!map.contains::<u32>());
|
||||||
/// ```
|
/// ```
|
||||||
pub fn remove<T: 'static>(&mut self) -> Option<T> {
|
pub fn remove<T: 'static>(&mut self) -> Option<T> {
|
||||||
self.map.remove(&TypeId::of::<T>()).and_then(downcast_owned)
|
self.map.remove(&TypeId::of::<T>()).and_then(downcast_rc)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clear the `Extensions` of all inserted extensions.
|
/// Clear the `Extensions` of all inserted extensions.
|
||||||
|
@ -128,6 +129,13 @@ impl Extensions {
|
||||||
pub(crate) fn drain_from(&mut self, other: &mut Self) {
|
pub(crate) fn drain_from(&mut self, other: &mut Self) {
|
||||||
self.map.extend(mem::take(&mut other.map));
|
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 {
|
impl fmt::Debug for Extensions {
|
||||||
|
@ -140,6 +148,49 @@ fn downcast_owned<T: 'static>(boxed: Box<dyn Any>) -> Option<T> {
|
||||||
boxed.downcast().ok().map(|boxed| *boxed)
|
boxed.downcast().ok().map(|boxed| *boxed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn downcast_rc<T: 'static>(boxed: Rc<dyn Any>) -> Option<T> {
|
||||||
|
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<TypeId, Rc<dyn Any>>,
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 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::<u32>().unwrap(), 2u32);
|
||||||
|
// /// ```
|
||||||
|
// pub fn insert<T: Clone + 'static>(&mut self, val: T) -> Option<T> {
|
||||||
|
// self.map
|
||||||
|
// .insert(TypeId::of::<T>(), Rc::new(val))
|
||||||
|
// .and_then(downcast_rc)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -119,7 +119,7 @@ impl OnConnectData {
|
||||||
on_connect_ext: Option<&ConnectCallback<T>>,
|
on_connect_ext: Option<&ConnectCallback<T>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let ext = on_connect_ext.map(|handler| {
|
let ext = on_connect_ext.map(|handler| {
|
||||||
let mut extensions = Extensions::new();
|
let mut extensions = Extensions::default();
|
||||||
handler(io, &mut extensions);
|
handler(io, &mut extensions);
|
||||||
extensions
|
extensions
|
||||||
});
|
});
|
||||||
|
@ -130,8 +130,8 @@ impl OnConnectData {
|
||||||
/// Merge self into given request's extensions.
|
/// Merge self into given request's extensions.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn merge_into(&mut self, req: &mut Request) {
|
pub(crate) fn merge_into(&mut self, req: &mut Request) {
|
||||||
if let Some(ref mut ext) = self.0 {
|
if let Some(ref ext) = self.0 {
|
||||||
req.head.extensions.get_mut().drain_from(ext);
|
req.head.extensions.get_mut().clone_from(ext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,10 +107,10 @@ where
|
||||||
/// It will receive a `&std::any::Any`, which contains underlying connection type and an
|
/// 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.
|
/// [Extensions] container so that request-local data can be passed to middleware and handlers.
|
||||||
///
|
///
|
||||||
/// For example:
|
/// # Connection Types
|
||||||
/// - `actix_tls::openssl::SslStream<actix_web::rt::net::TcpStream>` when using openssl.
|
/// - `actix_web::rt::net::TcpStream` when no TLS layer is used.
|
||||||
/// - `actix_tls::rustls::TlsStream<actix_web::rt::net::TcpStream>` when using rustls.
|
/// - `actix_tls::rustls::TlsStream<actix_web::rt::net::TcpStream>` when using rustls.
|
||||||
/// - `actix_web::rt::net::TcpStream` when no encryption is used.
|
/// - `actix_tls::openssl::SslStream<actix_web::rt::net::TcpStream>` when using openssl.
|
||||||
///
|
///
|
||||||
/// See `on_connect` example for additional details.
|
/// See `on_connect` example for additional details.
|
||||||
pub fn on_connect<CB>(self, f: CB) -> HttpServer<F, I, S, B>
|
pub fn on_connect<CB>(self, f: CB) -> HttpServer<F, I, S, B>
|
||||||
|
|
Loading…
Reference in a new issue