softprops / hyperlocal

🔌 ✨rustlang hyper bindings for local unix domain sockets
MIT License
227 stars 46 forks source link

UnixListener::from_std causes the server to hang #47

Closed kornelski closed 3 years ago

kornelski commented 3 years ago

This code used to work fine in hyperlocal 0.7 and the old tokio. In hyperlocal 0.8 and tokio 1.x the service_fn callback never sees any requests coming, and the client is stuck waiting for a response forever.

In 0.8 the server works fine only with a tokio UnixListener created directly from a path. It hangs if the listener has been converted from its std version.

#[tokio::test]
async fn hyperserve() {
    use hyper::{Server, Client, Body, Response, service::{make_service_fn, service_fn}};
    use hyperlocal::{UnixClientExt, Uri};

    let socket_path = "/tmp/test-hyperlocal.sock";
    let _ = std::fs::remove_file(socket_path);

    let make_service = make_service_fn(|_| async {
        Ok::<_, hyper::Error>(service_fn(|_req| async {
            Ok::<_, hyper::Error>(Response::new(Body::from("It works!")))
        }))
    });

    // Tokio listener created directly from path works fine:
    // let listener = tokio::net::UnixListener::bind(socket_path).unwrap();

    // Tokio listener created via std listener never responds:
    let listener = tokio::net::UnixListener::from_std(
        std::os::unix::net::UnixListener::bind(&socket_path).unwrap()
    ).unwrap();
    let builder = Server::builder(SocketIncoming::from_listener(listener));

    tokio::spawn(builder.serve(make_service));

    let client = Client::unix();
    let uri: hyper::Uri = Uri::new(socket_path, "/").into();
    let res = client.get(uri).await.unwrap();
    assert_eq!("It works!", hyper::body::to_bytes(res.into_body()).await.unwrap());
}
Darksonn commented 3 years ago

This is because you must manually set the socket in non-blocking mode before calling from_std.