有什么办法可以在hyper的同一个端口上运行Tungstenite?

时间:2018-06-21 19:00:40

标签: https rust

我正在尝试在Rust中制作一个用于简单浏览器游戏的Web服务器。我希望服务器能够通过HTTPS传递页面,但也能够通过WebSockets进行通信。我打算将此服务器放在Heroku上,但是由于它们每个应用程序只允许一个端口,因此我必须使WebSocket服务器与其他HTTPS代码在同一端口上运行。

看起来像this is possible with crates like rust-websocket,但该板条箱使用的是hyper的过时版本,似乎已不再维护。板条箱tokio_tungstenite是最新的。

问题是hypertungstenite都有自己的HTTP协议实现,WebSocket不能通过HTTP协议在两者之间进行转换。这意味着,一旦hypertungstenite解析了HTTPS请求之后,就无法继续进行其他部分的处理,因此您无法真正尝试连接WebSocket并匹配tungstenite中的错误并由hyper处理,也不能由hyper解析该请求并检查它是否是WebSocket请求并将其发送到tungstenite。有什么办法可以解决这个问题?

2 个答案:

答案 0 :(得分:1)

我认为应该可以这样做,tungstenitetokio-tungstenite允许您指定自定义标头(有辅助功能,其前缀为hdr),因此取决于在您使用的hyper版本上,如果可以将请求转换为某种形式,则可以提取标题时,可以将其传递给tungstenite

您可能还想尝试warp板条箱,它是建立在hyper之上的,它在后台使用了tungstenite来提供websocket支持,因此,如果要编写自己的板条箱版本warp,您可以看一下源代码(源代码可能包含有关如何一起使用hypertungstenite的提示)。

答案 1 :(得分:1)

您可以做到,但是很简单。您将必须使用tokio-tungstenite,自己进行握手(检查标头,设置响应标头),并在运行Websockets连接的运行时中产生新的未来。可以通过使用最新版本的hyper调用请求主体上的on_upgrade()来创建新的Future,然后可以将连接传递到tokio_tungstenite::WebSocketStream::from_raw_socket以将其转换为websockets连接。

示例处理程序(请注意,这不会完全检查请求标头,并假设我们要升级):

fn websocket(req: Request<Body>) -> Result<Response<Body>, &'static str> {
    // TODO check other header
    let key = match req.headers().typed_get::<headers::SecWebsocketKey>() {
        Some(key) => key,
        None => return Err("failed to read ws key from headers"),
    };
    let websocket_future = req
        .into_body()
        .on_upgrade()
        .map_err(|err| eprintln!("Error on upgrade: {}", err))
        .and_then(|upgraded| {
            let ws_stream = tokio_tungstenite::WebSocketStream::from_raw_socket(
                upgraded,
                tokio_tungstenite::tungstenite::protocol::Role::Server,
                None,
            );
            let (sink, stream) = ws_stream.split();
            sink.send_all(stream)
                .map(|_| ())
                .map_err(|err| error!("{}", err))
        });
    hyper::rt::spawn(websocket_future);
    let mut upgrade_rsp = Response::builder()
        .status(StatusCode::SWITCHING_PROTOCOLS)
        .body(Body::empty())
        .unwrap();
    upgrade_rsp
        .headers_mut()
        .typed_insert(headers::Upgrade::websocket());
    upgrade_rsp
        .headers_mut()
        .typed_insert(headers::Connection::upgrade());
    upgrade_rsp
        .headers_mut()
        .typed_insert(headers::SecWebsocketAccept::from(key));
    Ok(upgrade_rsp)
}