/* There are three kinds of OSC terminators: \x07, \x1b\x5c or \x9c. We only support
* the first two, because the last one is a valid UTF-8 codepoint and hence creates
* an ambiguity (many Terminal emulators refuse to support it as well). */
- if (eot || (!IN_SET(*i, '\x07', '\x1b') && (uint8_t) *i < 32U) || (uint8_t) *i > 126U) { /* EOT or invalid chars in sequence */
+ if (eot || (!IN_SET(*i, '\x07', '\x1b') && !osc_char_is_valid(*i))) { /* EOT or invalid chars in sequence */
fputc('\x1B', f);
fputc(']', f);
advance_offsets(i - *ibuf, highlight, shift, 2);
int pty_open_peer_racefree(int fd, int mode);
int pty_open_peer(int fd, int mode);
+
+static inline bool osc_char_is_valid(char c) {
+ /* Checks whether the specified character is safe to be included inside an ANSI OSC sequence, as per
+ * ECMA-48 5th edition, section 8.3.89 */
+ return (unsigned char) c >= 32U && (unsigned char) c < 127;
+}
#endif
}
+static bool url_suitable_for_osc8(const char *url) {
+ assert(url);
+
+ /* Not all URLs are safe for inclusion in OSC 8 due to charset and length restrictions. Let's detect
+ * which ones those are */
+
+ /* If the URL is longer than 2K let's not try to do OSC 8. As per recommendation in
+ * https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda#length-limits */
+ if (strlen(url) > 2000)
+ return false;
+
+ /* OSC sequences may only contain chars from the 32..126 range, as per ECMA-48 */
+ for (const char *c = url; *c; c++)
+ if (!osc_char_is_valid(*c))
+ return false;
+
+ return true;
+}
+
int terminal_urlify(const char *url, const char *text, char **ret) {
char *n;
if (isempty(text))
text = url;
- if (urlify_enabled())
+ if (urlify_enabled() && url_suitable_for_osc8(url))
n = strjoin(ANSI_OSC "8;;", url, ANSI_ST,
text,
ANSI_OSC "8;;" ANSI_ST);