actix / actix-web

Actix Web is a powerful, pragmatic, and extremely fast web framework for Rust.
https://actix.rs
Apache License 2.0
21.4k stars 1.66k forks source link

websocket problem with ssl(h2) #1069

Open kollapsderwellenfunktion opened 5 years ago

kollapsderwellenfunktion commented 5 years ago

i have a running actix server based on the websocket-chat example. everything works fine. but when i add ssl support, i can't connect with a client based on examples/websocket/src/client.rs. i get an error "Error: Tunnels are not supported for http2 connection". the browsers still work fine with h2. without ssl chrome is using http 1.1, with it h2. i now there was some problem with the websocket/h2 story in the past...

is there a way around this, or a way to force HttpServer or Client to use http 1.1 ?

fafhrd91 commented 5 years ago

Is this actix-web client error?

kollapsderwellenfunktion commented 5 years ago

yes. it's the Client::new().ws("https://foo/ws").connect()function that returns the error.

little-eagle commented 5 years ago

I am also suffering from the same issue.

  awc::Client::new()
            .ws("wss://stream.binance.com:9443/ws/btcusdt@trade")
            .connect()
            .map_err(|e| {
                println!("Error: {}", e);
            })

And posted in the gitter chat now before I saw this.

rustrust commented 5 years ago

1006 would probably help

jgarzik commented 4 years ago

Same issue here. Versions:

$ grep actix Cargo.toml 
actix = "^0.8.3"
actix-rt = "^0.2.2"
actix-web = { version="^1.0.0", features=["ssl"] }
actix-codec = "^0.1.2"

Code:

const BITTREX_API: &'static str = "https://api.bittrex.com/v3";
...
    actix::Arbiter::spawn(lazy(|| {
        Client::new()
            .ws(BITTREX_API)
            .connect()
            .map_err(|e| {
                println!("Error: {}", e);
            })
            .map(|(response, framed)| {
                println!("{:?}", response);
                let (sink, stream) = framed.split();
                let addr = ChatClient::create(|ctx| {
                    ChatClient::add_stream(stream, ctx);
                    ChatClient(SinkWrite::new(sink, ctx))
                });
            })
    }));
codeb2cc commented 4 years ago

Use custom connector to force HTTP 1.1 only in ALPN extension:

let ssl = {
    let mut ssl = openssl::ssl:SslConnector::builder(openssl::ssl:SslMethod::tls()).unwrap();
    let _ = ssl.set_alpn_protos(b"\x08http/1.1");
    ssl.build()
};
let connector = awc::Connector::new().ssl(ssl).finish();
awc::ClientBuilder::new()
    .connector(connector)
    .finish()
    .ws("wss://XXX");
codeb2cc commented 4 years ago

If you're using rust-tls, take a look at actix-http/src/client/connector.rs and use the corresponding method to set ALPN.

aumetra commented 4 years ago

Same issue here.

Snippet:

let client = awc::Client::new();

client
    .ws("wss://[URL here]")
    .connect()
    .await;

Versions in Cargo.toml:

actix-rt = "1.0"
awc = { version = "1.0", features = [ "rustls" ] }
Darkspirit commented 4 years ago

Websockets must use http/1.1 as long as RFC8441 is not implemented. I assume we are waiting for https://github.com/hyperium/h2/issues/347? Firefox seems to support it by default. Roughly this should be the code for Rustls:

# rustls = "0.16"
# webpki-roots = "0.18"

let mut cfg = rustls::ClientConfig::new();
cfg.alpn_protocols = vec![b"http/1.1".to_vec()];
cfg.root_store.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
let connector = awc::Connector::new().rustls(Arc::new(cfg)).finish();
let client = awc::ClientBuilder::new().connector(connector).finish();

client
    .ws("wss://[URL here]")
    .connect()
    .await;
lastagile commented 4 years ago

Websockets must use http/1.1 as long as RFC8441 is not implemented. I assume we are waiting for hyperium/h2#347? Firefox seems to support it by default. Roughly this should be the code for Rustls:

# rustls = "0.16"
# webpki-roots = "0.18"

let mut cfg = rustls::ClientConfig::new();
cfg.alpn_protocols = vec![b"http/1.1".to_vec()];
cfg.root_store.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
let connector = awc::Connector::new().rustls(Arc::new(cfg)).finish();
let client = awc::ClientBuilder::new().connector(connector).finish();

client
    .ws("wss://[URL here]")
    .connect()
    .await;

This works

fakeshadow commented 3 years ago

You can just use this API to set max http version instead of constructing connector yourself.

let client = awc::Client::builder()
        .max_http_version(awc::http::Version::HTTP_11)
        .finish();