From: "Fabian Grünbichler" <f.gruenbichler@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH proxmox 2/2] http: websocket: add proxy helper
Date: Wed, 5 Nov 2025 15:13:08 +0100 [thread overview]
Message-ID: <20251105141335.1230493-7-f.gruenbichler@proxmox.com> (raw)
In-Reply-To: <20251105141335.1230493-1-f.gruenbichler@proxmox.com>
allows wiring up two websocket connections so that decoded data from upstream
is sent forward downstream encoded as websocket frames, and vice versa, all
while handling control frames.
the preamble is used to inject an authentication line for xtermjs/termproxy by
PDM.
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
proxmox-http/src/websocket/mod.rs | 67 +++++++++++++++++++++++++++++++
1 file changed, 67 insertions(+)
diff --git a/proxmox-http/src/websocket/mod.rs b/proxmox-http/src/websocket/mod.rs
index eb808b52..4bf47eb2 100644
--- a/proxmox-http/src/websocket/mod.rs
+++ b/proxmox-http/src/websocket/mod.rs
@@ -821,4 +821,71 @@ impl WebSocket {
}
}
}
+
+ /// Takes two websocket endpoints and connects them by re-encoding the data.
+ ///
+ /// This method takes care of copying the data between endpoints, and sending correct responses
+ /// for control frames (e.g. a Point to a Ping).
+ ///
+ /// The `preamble` allows injecting initial handshake data into the proxying.
+ pub async fn proxy_connection<S, L>(
+ &self,
+ upstream: S,
+ downstream: L,
+ preamble: &[u8],
+ ) -> Result<(), Error>
+ where
+ S: AsyncRead + AsyncWrite + Unpin + Send + 'static,
+ L: AsyncRead + AsyncWrite + Unpin + Send + 'static,
+ {
+ // unmasked as the spec requires
+ let server_socket = WebSocket { mask: None };
+
+ // split to allow duplex transfer
+ let (upstream_raw_reader, upstream_raw_writer) = tokio::io::split(upstream);
+ let (downstream_raw_reader, downstream_raw_writer) = tokio::io::split(downstream);
+
+ // wire up WS handling for upstream connection
+ let (upstream_control_tx, mut upstream_control_rx) = mpsc::unbounded_channel();
+ let mut upstream_ws_reader = WebSocketReader::new(upstream_raw_reader, upstream_control_tx);
+ let mut upstream_ws_writer = WebSocketWriter::new(server_socket.mask, upstream_raw_writer);
+
+ // wire up WS handling for downstream connection
+ let (downstream_control_tx, mut downstream_control_rx) = mpsc::unbounded_channel();
+ let mut downstream_ws_reader =
+ WebSocketReader::new(downstream_raw_reader, downstream_control_tx);
+ let mut downstream_ws_writer = WebSocketWriter::new(self.mask, downstream_raw_writer);
+
+ // send preamble downstream via WS
+ if !preamble.is_empty() {
+ downstream_ws_writer.write_all(preamble).await?;
+ }
+
+ // read from upstream, write to downstream while handling control frames received from
+ // downstream
+ let downstream_future = server_socket.copy_to_websocket(
+ &mut upstream_ws_reader,
+ &mut downstream_ws_writer,
+ &mut downstream_control_rx,
+ );
+
+ // read from downstream, write to upstream while handling control frames received from
+ // upstream
+ let upstream_future = self.copy_to_websocket(
+ &mut downstream_ws_reader,
+ &mut upstream_ws_writer,
+ &mut upstream_control_rx,
+ );
+
+ select! {
+ res = downstream_future.fuse() => match res {
+ Ok(_) => Ok(()),
+ Err(err) => Err(Error::from(err)),
+ },
+ res = upstream_future.fuse() => match res {
+ Ok(_) => Ok(()),
+ Err(err) => Err(Error::from(err)),
+ },
+ }
+ }
}
--
2.47.3
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
next prev parent reply other threads:[~2025-11-05 14:14 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-11-05 14:13 [pve-devel] [RFC access-control/manager/proxmox{, -yew-comp, -datacenter-manager}/xtermjs 00/11] add remote node shell Fabian Grünbichler
2025-11-05 14:13 ` [pve-devel] [PATCH pve-xtermjs 1/1] xtermjs: add support for remote node shells via PDM Fabian Grünbichler
2025-11-05 14:13 ` [pve-devel] [PATCH access-control 1/1] api: ticket: allow token-owned VNC ticket verification Fabian Grünbichler
2025-11-05 14:13 ` [pve-devel] [PATCH manager 1/2] api: termproxy/vncwebsocket: allow tokens Fabian Grünbichler
2025-11-05 14:13 ` [pve-devel] [PATCH manager 2/2] api: termproxy: add description to return schema Fabian Grünbichler
2025-11-05 14:13 ` [pve-devel] [PATCH proxmox 1/2] pve-api-types: add termproxy call and types Fabian Grünbichler
2025-11-05 14:13 ` Fabian Grünbichler [this message]
2025-11-05 14:13 ` [pve-devel] [PATCH proxmox-yew-comp 1/1] xtermjs: add remote support Fabian Grünbichler
2025-11-05 14:13 ` [pve-devel] [PATCH proxmox-datacenter-manager 1/4] connection: add access to "raw" client Fabian Grünbichler
2025-11-05 14:13 ` [pve-devel] [PATCH proxmox-datacenter-manager 2/4] api: pve: add termproxy endpoint Fabian Grünbichler
2025-11-05 14:13 ` [pve-devel] [PATCH proxmox-datacenter-manager 3/4] api: pve: add vncwebsocket endpoint Fabian Grünbichler
2025-11-05 14:13 ` [pve-devel] [PATCH proxmox-datacenter-manager 4/4] ui: pve: node: add shell tab Fabian Grünbichler
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20251105141335.1230493-7-f.gruenbichler@proxmox.com \
--to=f.gruenbichler@proxmox.com \
--cc=pve-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox