snapview / tokio-tungstenite

Future-based Tungstenite for Tokio. Lightweight stream-based WebSocket implementation
MIT License
1.88k stars 236 forks source link

Adding authorization header leads in infinite block of connect_async #327

Closed Tockra closed 7 months ago

Tockra commented 7 months ago

Hi,

I'm trying to test my websocket implementation by using tokio_tungstenite. For that I build a small mapper function receiving a SocketAddr, endpoint and auth_token:

pub async fn get_websocket_connection(
    addr: SocketAddr,
    endpoint: &str,
    auth_token: &str,
) -> WebSocketStream<MaybeTlsStream<TcpStream>> {
    let port = addr.port();
    let host = format!("ws://127.0.0.1:{port}{endpoint}");
    let (socket, response) = tokio_tungstenite::connect_async(
        Request::builder()
            .uri(host.clone())
            .header("Authorization", format!("Bearer {}", auth_token))
            .header("Host", format!("127.0.0.1:{port}"))
            .header("Connection", "Upgrade")
            .header("Upgrade", "websocket")
            .header("Sec-WebSocket-Version", "13")
            .header(
                "Sec-WebSocket-Key",
                tokio_tungstenite::tungstenite::handshake::client::generate_key(),
            )
            .body(())
            .unwrap(),
    )
    .await
    .unwrap();
    assert_eq!(response.status(), StatusCode::OK);
    socket
}

This connection seems not to work. My test blocks longer than 60 seconds here. If I place a wait (15 seconds) before the connect_async it works. I think the application does not provide the endpoints but the connect_async already tries to connect. But I can not explain why it blocks infinite. I don't want to place a hardcoded wait into my tests. Otherwise the test will burn time and I never can be sure if the waiting time is high enough on computers with low performance.

Some thoughts?

daniel-abramov commented 7 months ago

There is likely certain logic/processing in your app/tests that leads to such behavior - I can't tell more because I don't have a source code of a client/server. There is no special processing of authorization headers within tungstenite or tokio-tungstenite, so the behavior that you described cannot stem from our crate.

If you could provide a simple self-contained reproducible example of the client/server, we may try to help by checking if something is wrong with the way the crate is used, but I can't really judge about the client/server based on the provided snippet that just adds a couple of headers.

The only suggestion that I can give so far is that you typically don't need to generate Upgrade, Sec-WebSocket-Version and other headers. You can just call into_client_request() on your URL and add the authentication header if that's what you need.

Tockra commented 7 months ago

Okay thank you. I tried to build a small example which reproduces it, but I cant.

Maybe the reason for that is the authorization middleware I'm using: https://crates.io/crates/axum-keycloak-auth