mirror of
https://github.com/actix/actix-extras.git
synced 2024-11-28 01:32:57 +01:00
add unsafe checks #331
This commit is contained in:
parent
c2c4a5ba3f
commit
ebc59cf7b9
80
src/with.rs
80
src/with.rs
@ -111,8 +111,18 @@ where
|
|||||||
T: FromRequest<S>,
|
T: FromRequest<S>,
|
||||||
S: 'static,
|
S: 'static,
|
||||||
{
|
{
|
||||||
hnd: Rc<UnsafeCell<F>>,
|
hnd: Rc<WithHnd<T, S, F, R>>,
|
||||||
cfg: ExtractorConfig<S, T>,
|
cfg: ExtractorConfig<S, T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct WithHnd<T, S, F, R>
|
||||||
|
where
|
||||||
|
F: Fn(T) -> R,
|
||||||
|
T: FromRequest<S>,
|
||||||
|
S: 'static,
|
||||||
|
{
|
||||||
|
hnd: Rc<UnsafeCell<F>>,
|
||||||
|
_t: PhantomData<T>,
|
||||||
_s: PhantomData<S>,
|
_s: PhantomData<S>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,8 +135,11 @@ where
|
|||||||
pub fn new(f: F, cfg: ExtractorConfig<S, T>) -> Self {
|
pub fn new(f: F, cfg: ExtractorConfig<S, T>) -> Self {
|
||||||
With {
|
With {
|
||||||
cfg,
|
cfg,
|
||||||
hnd: Rc::new(UnsafeCell::new(f)),
|
hnd: Rc::new(WithHnd {
|
||||||
_s: PhantomData,
|
hnd: Rc::new(UnsafeCell::new(f)),
|
||||||
|
_t: PhantomData,
|
||||||
|
_s: PhantomData,
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -166,7 +179,7 @@ where
|
|||||||
S: 'static,
|
S: 'static,
|
||||||
{
|
{
|
||||||
started: bool,
|
started: bool,
|
||||||
hnd: Rc<UnsafeCell<F>>,
|
hnd: Rc<WithHnd<T, S, F, R>>,
|
||||||
cfg: ExtractorConfig<S, T>,
|
cfg: ExtractorConfig<S, T>,
|
||||||
req: HttpRequest<S>,
|
req: HttpRequest<S>,
|
||||||
fut1: Option<Box<Future<Item = T, Error = Error>>>,
|
fut1: Option<Box<Future<Item = T, Error = Error>>>,
|
||||||
@ -206,20 +219,28 @@ where
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let hnd: &mut F = unsafe { &mut *self.hnd.get() };
|
let fut = {
|
||||||
let item = match (*hnd)(item).respond_to(&self.req) {
|
// clone handler, inicrease ref counter
|
||||||
Ok(item) => item.into(),
|
let h = self.hnd.as_ref().hnd.clone();
|
||||||
Err(e) => return Err(e.into()),
|
// Enforce invariants before entering unsafe code.
|
||||||
};
|
// Only two references could exists With struct owns one, and line above
|
||||||
|
if Rc::weak_count(&h) != 0 && Rc::strong_count(&h) != 2 {
|
||||||
match item.into() {
|
panic!("Multiple copies of handler are in use")
|
||||||
AsyncResultItem::Err(err) => Err(err),
|
|
||||||
AsyncResultItem::Ok(resp) => Ok(Async::Ready(resp)),
|
|
||||||
AsyncResultItem::Future(fut) => {
|
|
||||||
self.fut2 = Some(fut);
|
|
||||||
self.poll()
|
|
||||||
}
|
}
|
||||||
}
|
let hnd: &mut F = unsafe { &mut *h.as_ref().get() };
|
||||||
|
let item = match (*hnd)(item).respond_to(&self.req) {
|
||||||
|
Ok(item) => item.into(),
|
||||||
|
Err(e) => return Err(e.into()),
|
||||||
|
};
|
||||||
|
|
||||||
|
match item.into() {
|
||||||
|
AsyncResultItem::Err(err) => return Err(err),
|
||||||
|
AsyncResultItem::Ok(resp) => return Ok(Async::Ready(resp)),
|
||||||
|
AsyncResultItem::Future(fut) => fut,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.fut2 = Some(fut);
|
||||||
|
self.poll()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,9 +253,8 @@ where
|
|||||||
T: FromRequest<S>,
|
T: FromRequest<S>,
|
||||||
S: 'static,
|
S: 'static,
|
||||||
{
|
{
|
||||||
hnd: Rc<UnsafeCell<F>>,
|
hnd: Rc<WithHnd<T, S, F, R>>,
|
||||||
cfg: ExtractorConfig<S, T>,
|
cfg: ExtractorConfig<S, T>,
|
||||||
_s: PhantomData<S>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S, F, R, I, E> WithAsync<T, S, F, R, I, E>
|
impl<T, S, F, R, I, E> WithAsync<T, S, F, R, I, E>
|
||||||
@ -249,8 +269,11 @@ where
|
|||||||
pub fn new(f: F, cfg: ExtractorConfig<S, T>) -> Self {
|
pub fn new(f: F, cfg: ExtractorConfig<S, T>) -> Self {
|
||||||
WithAsync {
|
WithAsync {
|
||||||
cfg,
|
cfg,
|
||||||
hnd: Rc::new(UnsafeCell::new(f)),
|
hnd: Rc::new(WithHnd {
|
||||||
_s: PhantomData,
|
hnd: Rc::new(UnsafeCell::new(f)),
|
||||||
|
_s: PhantomData,
|
||||||
|
_t: PhantomData,
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -295,7 +318,7 @@ where
|
|||||||
S: 'static,
|
S: 'static,
|
||||||
{
|
{
|
||||||
started: bool,
|
started: bool,
|
||||||
hnd: Rc<UnsafeCell<F>>,
|
hnd: Rc<WithHnd<T, S, F, R>>,
|
||||||
cfg: ExtractorConfig<S, T>,
|
cfg: ExtractorConfig<S, T>,
|
||||||
req: HttpRequest<S>,
|
req: HttpRequest<S>,
|
||||||
fut1: Option<Box<Future<Item = T, Error = Error>>>,
|
fut1: Option<Box<Future<Item = T, Error = Error>>>,
|
||||||
@ -356,8 +379,17 @@ where
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let hnd: &mut F = unsafe { &mut *self.hnd.get() };
|
self.fut2 = {
|
||||||
self.fut2 = Some((*hnd)(item));
|
// clone handler, inicrease ref counter
|
||||||
|
let h = self.hnd.as_ref().hnd.clone();
|
||||||
|
// Enforce invariants before entering unsafe code.
|
||||||
|
// Only two references could exists With struct owns one, and line above
|
||||||
|
if Rc::weak_count(&h) != 0 && Rc::strong_count(&h) != 2 {
|
||||||
|
panic!("Multiple copies of handler are in use")
|
||||||
|
}
|
||||||
|
let hnd: &mut F = unsafe { &mut *h.as_ref().get() };
|
||||||
|
Some((*hnd)(item))
|
||||||
|
};
|
||||||
self.poll()
|
self.poll()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,28 @@ fn test_path_extractor() {
|
|||||||
assert_eq!(bytes, Bytes::from_static(b"Welcome test!"));
|
assert_eq!(bytes, Bytes::from_static(b"Welcome test!"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_async_handler() {
|
||||||
|
let mut srv = test::TestServer::new(|app| {
|
||||||
|
app.resource("/{username}/index.html", |r| {
|
||||||
|
r.route().with(|p: Path<PParam>| {
|
||||||
|
Delay::new(Instant::now() + Duration::from_millis(10))
|
||||||
|
.and_then(move |_| Ok(format!("Welcome {}!", p.username)))
|
||||||
|
.responder()
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// client request
|
||||||
|
let request = srv.get().uri(srv.url("/test/index.html")).finish().unwrap();
|
||||||
|
let response = srv.execute(request.send()).unwrap();
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
|
// read response
|
||||||
|
let bytes = srv.execute(response.body()).unwrap();
|
||||||
|
assert_eq!(bytes, Bytes::from_static(b"Welcome test!"));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_query_extractor() {
|
fn test_query_extractor() {
|
||||||
let mut srv = test::TestServer::new(|app| {
|
let mut srv = test::TestServer::new(|app| {
|
||||||
|
Loading…
Reference in New Issue
Block a user