headroom/crates/headroom-proxy/tests/integration_ws.rs
dependabot[bot] bbe901319d
deps: bump tokio-tungstenite from 0.24.0 to 0.30.0 (#2967)
Bumps [tokio-tungstenite](https://github.com/snapview/tokio-tungstenite)
from 0.24.0 to 0.30.0.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/snapview/tokio-tungstenite/blob/master/CHANGELOG.md">tokio-tungstenite's
changelog</a>.</em></p>
<blockquote>
<h1>0.30.0</h1>
<ul>
<li>Update <code>tungstenite</code> to <code>0.30.0</code>. See <a
href="https://github.com/snapview/tungstenite-rs/blob/master/CHANGELOG.md"><code>tungstenite</code>
release</a>.</li>
</ul>
<h1>0.29.0</h1>
<ul>
<li>Update <code>tungstenite</code> to <code>0.29.0</code>. See <a
href="https://github.com/snapview/tungstenite-rs/blob/master/CHANGELOG.md"><code>tungstenite</code>
release</a>.</li>
</ul>
<h1>0.28.0</h1>
<ul>
<li>Update <code>tungstenite</code> to <code>0.28.0</code>. See <a
href="https://github.com/snapview/tungstenite-rs/blob/master/CHANGELOG.md"><code>tungstenite</code>
release</a>.</li>
</ul>
<h1>0.27.0</h1>
<ul>
<li>See <a
href="https://github.com/snapview/tungstenite-rs/blob/master/CHANGELOG.md#0270">performance
updates in <code>tungstenite-rs</code></a>.</li>
</ul>
<h1>0.26.2</h1>
<ul>
<li>Update <code>tungstenite</code>, see <a
href="https://github.com/snapview/tungstenite-rs/blob/master/CHANGELOG.md#0262">changes
here</a>.</li>
</ul>
<h1>0.26.1</h1>
<ul>
<li>Update <code>tungstenite</code> to address an issue that might cause
UB in certain cases.</li>
</ul>
<h1>0.26.0</h1>
<ul>
<li>Update <code>tungstenite</code> to <code>0.26.0</code> (<a
href="https://github.com/snapview/tungstenite-rs/blob/master/CHANGELOG.md#0260">breaking
changes</a>).</li>
</ul>
<h1>0.25.0</h1>
<ul>
<li>Update <code>tungstenite</code> to <code>0.25.0</code> (<a
href="https://github.com/snapview/tungstenite-rs/blob/master/CHANGELOG.md#0250">important
updates!</a>).</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="4994a07803"><code>4994a07</code></a>
Bump version</li>
<li><a
href="753ca72690"><code>753ca72</code></a>
Document cancel safety of reading from WebSocketStream (<a
href="https://redirect.github.com/snapview/tokio-tungstenite/issues/378">#378</a>)</li>
<li><a
href="751d7e2bc2"><code>751d7e2</code></a>
Update version number listed in Readme (<a
href="https://redirect.github.com/snapview/tokio-tungstenite/issues/375">#375</a>)</li>
<li><a
href="57fc3d0276"><code>57fc3d0</code></a>
docs(CHANGELOG.md): fix <code>tungstenite</code> versions (<a
href="https://redirect.github.com/snapview/tokio-tungstenite/issues/374">#374</a>)</li>
<li><a
href="7930ff2f82"><code>7930ff2</code></a>
Bump version</li>
<li><a
href="38d04656fe"><code>38d0465</code></a>
Update Readme (<a
href="https://redirect.github.com/snapview/tokio-tungstenite/issues/369">#369</a>)</li>
<li><a
href="35d110c24c"><code>35d110c</code></a>
Implement into_inner to get the underlying stream (<a
href="https://redirect.github.com/snapview/tokio-tungstenite/issues/367">#367</a>)</li>
<li><a
href="f3ae75d1de"><code>f3ae75d</code></a>
Update <code>tungstenite</code> version and fix bugs</li>
<li><a
href="25b544e43f"><code>25b544e</code></a>
Allow getting a reference to the shared inner stream (<a
href="https://redirect.github.com/snapview/tokio-tungstenite/issues/363">#363</a>)</li>
<li><a
href="e855f9eb8c"><code>e855f9e</code></a>
Fix errors in the examples caused by <code>Utf8Error</code></li>
<li>Additional commits viewable in <a
href="https://github.com/snapview/tokio-tungstenite/compare/v0.24.0...v0.30.0">compare
view</a></li>
</ul>
</details>
<br />

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: JerrettDavis <mxjerrett@gmail.com>
2026-08-14 10:50:15 -05:00

96 lines
3.5 KiB
Rust

//! WebSocket proxy: bidirectional pump + close propagation.
mod common;
use std::net::SocketAddr;
use std::time::Duration;
use common::start_proxy;
use futures_util::{SinkExt, StreamExt};
use tokio_tungstenite::tungstenite::protocol::CloseFrame;
use tokio_tungstenite::tungstenite::Message;
/// Spawns an upstream WS echo server. Handshake uses tungstenite over a raw TCP listener.
async fn echo_upstream() -> (SocketAddr, tokio::sync::oneshot::Sender<()>) {
let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
let addr = listener.local_addr().unwrap();
let (stop_tx, mut stop_rx) = tokio::sync::oneshot::channel();
tokio::spawn(async move {
loop {
tokio::select! {
_ = &mut stop_rx => break,
accepted = listener.accept() => {
let Ok((stream, _)) = accepted else { continue };
tokio::spawn(async move {
let Ok(ws) = tokio_tungstenite::accept_async(stream).await else { return };
let (mut sink, mut src) = ws.split();
while let Some(Ok(msg)) = src.next().await {
match msg {
Message::Close(cf) => {
let _ = sink.send(Message::Close(cf)).await;
break;
}
m => {
if sink.send(m).await.is_err() { break; }
}
}
}
});
}
}
}
});
(addr, stop_tx)
}
#[tokio::test]
async fn ws_text_and_binary_round_trip() {
let (upstream_addr, _stop) = echo_upstream().await;
let proxy = start_proxy(&format!("http://{upstream_addr}")).await;
let url = format!("{}/ws", proxy.ws_url());
let (mut ws, _) = tokio_tungstenite::connect_async(&url).await.unwrap();
for i in 0..5 {
let m = format!("hello-{i}");
ws.send(Message::Text(m.clone().into())).await.unwrap();
let echoed = ws.next().await.unwrap().unwrap();
match echoed {
Message::Text(t) => assert_eq!(t.as_str(), m),
other => panic!("expected text, got {other:?}"),
}
}
for i in 0..5u8 {
let m: Vec<u8> = (0..32u8).map(|b| b ^ i).collect();
ws.send(Message::Binary(m.clone().into())).await.unwrap();
let echoed = ws.next().await.unwrap().unwrap();
match echoed {
Message::Binary(b) => assert_eq!(b.to_vec(), m),
other => panic!("expected binary, got {other:?}"),
}
}
ws.send(Message::Close(None)).await.unwrap();
proxy.shutdown().await;
}
#[tokio::test]
async fn ws_client_close_propagates() {
let (upstream_addr, _stop) = echo_upstream().await;
let proxy = start_proxy(&format!("http://{upstream_addr}")).await;
let (mut ws, _) = tokio_tungstenite::connect_async(format!("{}/ws", proxy.ws_url()))
.await
.unwrap();
ws.send(Message::Close(Some(CloseFrame {
code: tokio_tungstenite::tungstenite::protocol::frame::coding::CloseCode::Normal,
reason: "bye".into(),
})))
.await
.unwrap();
// Server-side echo will reflect the close; we should see a Close back.
let got = tokio::time::timeout(Duration::from_secs(3), ws.next()).await;
assert!(got.is_ok(), "expected close echo within 3s");
proxy.shutdown().await;
}