Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ctrl + Space in the terminal crashes the session with: received invalid non-UTF8 text data #21213

Closed
thepragmaticmero opened this issue Oct 31, 2024 · 7 comments · Fixed by #21283
Assignees

Comments

@thepragmaticmero
Copy link

thepragmaticmero commented Oct 31, 2024

The shortcut Ctrl + Space is a hardcoded keyboard shortcut on the remote terminal https://ip:port/system/terminal, it closes the connection to the remote terminal. My configuration has Ctrl + Space as a leader key for tmux, the hardcoded shortcut inhibits the leader function on tmux. Disconnecting it.

Possible solutions:

  • Make the shortcut customizable.
  • Change the shortcut to something else.

Is there a cockpit.conf parameter that solves the problem maybe?

@garrett garrett transferred this issue from cockpit-project/cockpit-machines Nov 4, 2024
@garrett
Copy link
Member

garrett commented Nov 4, 2024

Note: I transferred this to the main Cockpit repo, instead of Cockpit Machines, as this appears to be related to the terminal in Cockpit (according to the URL), not the consoles in Cockpit Machines

I see this behavior on both the latest Firefox and Chrome on GNOME 47 on Fedora 41.

It's not an issue for the page itself, as hitting control+space doesn't do anything when the focus isn't on the widget, so I don't think it's intentional from the Cockpit side nor does it seem to be browser-related.

It does disconnect when you're focused on the terminal widget, so I'm thinking that it might be a bug in keyboard handling in the terminal JavaScript from xterm.js (which is what we use for the terminal). The demo at https://xtermjs.org/ doesn't close the session, however, so it might not be that, unless that has a fix our version doesn't have.

@jelly
Copy link
Member

jelly commented Nov 4, 2024

ctrl+space oopses cockpit for me and it shouldn't. So we should look into this.

@thepragmaticmero
Copy link
Author

It happened to me on firefox and on the Steam overlay browser (chromium).

@martinpitt
Copy link
Member

Indeed, it hard-crashes the session:

cockpit-ws[80319]: Received invalid WebSocket data from the server
cockpit-ws[80319]: received invalid non-UTF8 text data

That's rather disappointing, this is similar to issue #20791 which was fixed in commit eff7d97

@martinpitt martinpitt changed the title Ctrl + Space closing the remote terminal, I use that shortcut as tmux leader key Ctrl + Space in the terminal crashes the session with: received invalid non-UTF8 text data Nov 18, 2024
@martinpitt
Copy link
Member

martinpitt commented Nov 18, 2024

Notes:

  • Ctrl+Space is an unbreakable space, i.e. U+00A0, which is perfect unicode according to several references like https://unicode-explorer.com/c/00A0.
  • g_utf8_validate({0x20, 0xA0}, ..) is False! That's a glib bug. Unfortunately https://gitlab.gnome.org/GNOME/glib is down right now. Update: That is the code point, but the UTF-8 encoding is actually C2A0. Python does that as well. And g_utf8_validate({0xC2, 0xA0, 0x20}) is True.
  • An XTerm's onData() callback receives a String, apparently always, even for binary junk like pasting head -c50 /usr/bin/cat | wl-copy. That doesn't even upset ws.
  • Changing pkg/lib/cockpit-components-terminal.jsx 's onData() for sending binary instead:
--- pkg/lib/cockpit-components-terminal.jsx
+++ pkg/lib/cockpit-components-terminal.jsx
@@ -132,8 +132,11 @@ export class Terminal extends React.Component {
         this.terminalRef = React.createRef();
 
         term.onData(function(data) {
+            const e = new TextEncoder();
+            const bytes = e.encode(data);
+            console.log("terminal onData string", data, "bytes", bytes);
             if (this.props.channel.valid)
-                this.props.channel.send(data);
+                this.props.channel.send(bytes);
         }.bind(this));
 
         if (props.onTitleChanged)

generally works and stops the crash, but entirely ignores the Ctrl+Space, and encodes it as [0] 🤯

  • comparing the data string to data === '\xa0' or data === String.fromCharCode(0xa0) also fails. How on earth do I get a sane representation/comparison/encoding of a non-breakable space?? why is this so evil?
  • at first I thought this is all because the browser actually sends a null byte, but debugging cockpit-ws shows that it really receives a 0xA0. In particular, the whole frame it gets is 313a32a0 in hex, which decodes to "1:2" (the channel name) and then the nbsp.
  • However, in a JS console, new TextEncoder().encode(' ') (where thing in the middle is an nbsp) actually does give Uint8Array [ 194, 160 ], and sending that to the websocket works fine. So somehow Xterm.js mangles this.
  • Xterm's onBinary() callback isn't called for Ctrl+Space.
  • Calling btoa(data) confirms that the string really looks like a \x00\x00 in JavaScript, even though the internal representation must differ somehow as ws gets it as a single \xA0.

@martinpitt martinpitt self-assigned this Nov 18, 2024
martinpitt added a commit to martinpitt/cockpit that referenced this issue Nov 18, 2024
Pressing Ctrl+Space in the terminal was previously considered a major
insult and killed the session. Both the "externally visible"
representation in JS as a string (a null byte) as well as the actual
bytes sent to the websocket (0xA0) are broken and useless. The latter
caused a session disconnect due to invalid UTF-8 data, and the former
makes it impossible to properly work around this issue (which would be
to send [0xC2, 0xA0] to the web socket).

So the best thing that we can do is to ignore invalid keys (which show
up as NUL).

Fixes cockpit-project#21213
@martinpitt
Copy link
Member

@thepragmaticmero I sent a PR #21283 to fix the session killing, but I'm afraid Ctrl+Space still won't work for you -- it comes out of the browser as NUL byte, and the only thing we can do is to ignore it 😢

martinpitt added a commit to martinpitt/cockpit that referenced this issue Nov 18, 2024
Pressing Ctrl+Space in the terminal was previously considered a major
insult and killed the session. Both the "externally visible"
representation in JS as a string (a null byte) as well as the actual
bytes sent to the websocket (0xA0) are broken and useless. The latter
caused a session disconnect due to invalid UTF-8 data, and the former
makes it impossible to properly work around this issue (which would be
to send [0xC2, 0xA0] to the web socket).

So the best thing that we can do is to ignore invalid keys (which show
up as NUL).

Fixes cockpit-project#21213
@thepragmaticmero
Copy link
Author

I'll use a workaround then, revert to using Ctrl+B on my workflow it's fine for now.

martinpitt added a commit that referenced this issue Nov 19, 2024
Pressing Ctrl+Space in the terminal was previously considered a major
insult and killed the session. Both the "externally visible"
representation in JS as a string (a null byte) as well as the actual
bytes sent to the websocket (0xA0) are broken and useless. The latter
caused a session disconnect due to invalid UTF-8 data, and the former
makes it impossible to properly work around this issue (which would be
to send [0xC2, 0xA0] to the web socket).

So the best thing that we can do is to ignore invalid keys (which show
up as NUL).

Fixes #21213
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants