Hyper http service - Future cannot be sent between threads safely

hyper v0.13.0

I am implementing an HTTP server by following examples

pub fn start(port : u16, 
            cipher_key : &str,
            upstream_tx : UnboundedSender<InternalMessage>){


    let addr = ([0, 0, 0, 0], port).into();

    let server = Server::bind(&addr).http1_only(true).serve(MakeSvc{
        srv : Arc::new(StreamingServer::new(cipher_key, upstream_tx)),
    });


    tokio::spawn(async move {
        server.await.expect("hyper.server fault error");
    });
    
}

pub struct MakeSvc {
    srv : Arc<StreamingServer>
}

impl<T> Service<T> for MakeSvc {
    type Response = Svc;
    type Error = std::io::Error;
    type Future = future::Ready<Result<Self::Response, Self::Error>>;

    fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        Ok(()).into()
    }

    fn call(&mut self, _: T) -> Self::Future {
        future::ok(Svc{
            srv : self.srv.clone(),
        })
    }
}




pub struct Svc {
    srv : Arc<StreamingServer>
}

impl Service<Request<Body>> for Svc {
    type Response = Response<Body>;
    type Error = hyper::Error;
    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;

    fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        Ok(()).into()
    }

    fn call(&mut self, req: Request<Body>) -> Self::Future {

        let path : &str = req.uri().path();
        let len : usize = PATH_PREFIX.len() as usize;
        if req.method() == Method::PUT && path.starts_with(PATH_PREFIX) && path.len() > len  {
            let key = &path[len..].to_string();

            let ar = req.into_body()
                .map_err(|e| Error::new(ErrorKind::Other, format!("{:?}", e)) )
                .into_async_read();

            let srv = self.srv.clone();
            let fut = async move {
                srv.handle_client_request(key, ar).await;
                let rsp = Response::builder();

                let body = Body::from(Vec::new());
                let rsp = rsp.status(200).body(body).unwrap();
                Ok(rsp)
            };
            return Box::pin(fut)
        }



        let rsp = Response::builder();

        let body = Body::from(Vec::new());
        let rsp = rsp.status(404).body(body).unwrap();

        let fut = async {
            Ok(rsp)
        };
        Box::pin(fut)
    }
}

It seems I encounter thread-safety issue with Future, have no idea how to solve. Can any body help? Thank you in advance.

|     let server = Server::bind(&addr).http1_only(true).serve(MakeSvc{
|                                                       ^^^^^ `(dyn core::future::future::Future<Output = std::result::Result<http::response::Response<hyper::body::body::Body>, hyper::error::Error>> + 'static)` cannot be sent between threads safely
|
= help: the trait `std::marker::Send` is not implemented for `(dyn core::future::future::Future<Output = std::result::Result<http::response::Response<hyper::body::body::Body>, hyper::error::Error>> + 'static)`
= note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique<(dyn core::future::future::Future<Output = std::result::Result<http::response::Response<hyper::body::body::Body>, hyper::error::Error>> + 'static)>`
= note: required because it appears within the type `std::boxed::Box<(dyn core::future::future::Future<Output = std::result::Result<http::response::Response<hyper::body::body::Body>, hyper::error::Error>> + 'static)>`
= note: required because it appears within the type `std::pin::Pin<std::boxed::Box<(dyn core::future::future::Future<Output = std::result::Result<http::response::Response<hyper::body::body::Body>, hyper::error::Error>> + 'static)>>`
= note: required because it appears within the type `hyper::proto::h2::server::H2StreamState<std::pin::Pin<std::boxed::Box<(dyn core::future::future::Future<Output = std::result::Result<http::response::Response<hyper::body::body::Body>, hyper::error::Error>> + 'static)>>, hyper::body::body::Body>`
= note: required because it appears within the type `hyper::proto::h2::server::H2Stream<std::pin::Pin<std::boxed::Box<(dyn core::future::future::Future<Output = std::result::Result<http::response::Response<hyper::body::body::Body>, hyper::error::Error>> + 'static)>>, hyper::body::body::Body>`
= note: required because of the requirements on the impl of `hyper::common::exec::H2Exec<std::pin::Pin<std::boxed::Box<(dyn core::future::future::Future<Output = std::result::Result<http::response::Response<hyper::body::body::Body>, hyper::error::Error>> + 'static)>>, hyper::body::body::Body>` for `hyper::common::exec::Exec`

Try changing the future type to Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>

1 Like

What happened is that when you use dyn Trait, you lose knowledge about any properties of the type unless you explicitly list them in the dyn type. In this case you didn't explicitly tell it it was Send, so it didn't know if it was.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.