https://github.com/JDevlieghere created 
https://github.com/llvm/llvm-project/pull/206129

Host::OpenURL was only defined for Darwin (in Host.mm). Add a portable 
implementation in the common Host.cpp: on Unix it launches xdg-open; on Windows 
it returns "unsupported" for now. xdg-open is run without a shell 
(run_in_shell=false) so query-string metacharacters in the URL are never 
interpreted by the shell.

Also add Host::URLEncode, an RFC 3986 percent-encoder for assembling tracker 
URLs. These are the building blocks for an upcoming "diagnostics report" 
command that opens a pre-filled bug URL, and the encoder is shared with a 
downstream tap-to-radar reporter.

>From 7c0789cdc2e34777711df4706c9f9e2db6bd7337 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <[email protected]>
Date: Fri, 26 Jun 2026 09:46:58 -0700
Subject: [PATCH] [lldb] Add a non-Darwin Host::OpenURL and a Host::URLEncode
 helper

Host::OpenURL was only defined for Darwin (in Host.mm). Add a portable
implementation in the common Host.cpp: on Unix it launches xdg-open; on
Windows it returns "unsupported" for now. xdg-open is run without a
shell (run_in_shell=false) so query-string metacharacters in the URL
are never interpreted by the shell.

Also add Host::URLEncode, an RFC 3986 percent-encoder for assembling
tracker URLs. These are the building blocks for an upcoming
"diagnostics report" command that opens a pre-filled bug URL, and the
encoder is shared with a downstream tap-to-radar reporter.
---
 lldb/include/lldb/Host/Host.h    |  7 ++++
 lldb/source/Host/common/Host.cpp | 56 ++++++++++++++++++++++++++++++++
 lldb/unittests/Host/HostTest.cpp | 11 +++++++
 3 files changed, 74 insertions(+)

diff --git a/lldb/include/lldb/Host/Host.h b/lldb/include/lldb/Host/Host.h
index 4538fd206251b..632614c17d173 100644
--- a/lldb/include/lldb/Host/Host.h
+++ b/lldb/include/lldb/Host/Host.h
@@ -311,8 +311,15 @@ class Host {
                                               const FileSpec &file_spec,
                                               uint32_t line_no);
 
+  /// Open a URL with the host's default handler (Launch Services on macOS,
+  /// xdg-open on other Unix). Returns an error if opening fails or the 
platform
+  /// has no implementation (e.g. Windows).
   static llvm::Error OpenURL(llvm::StringRef url);
 
+  /// Percent-encode a string for use in a URL query component, per RFC 3986
+  /// (alphanumerics and "-_.~" are kept literal; everything else becomes %HH).
+  static std::string URLEncode(llvm::StringRef str);
+
   /// Check if we're running in an interactive graphical session.
   ///
   /// \return
diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp
index 68456e199cd04..b7a1020b4abd3 100644
--- a/lldb/source/Host/common/Host.cpp
+++ b/lldb/source/Host/common/Host.cpp
@@ -7,6 +7,7 @@
 
//===----------------------------------------------------------------------===//
 
 // C includes
+#include <cctype>
 #include <cerrno>
 #include <climits>
 #include <cstdlib>
@@ -49,6 +50,7 @@
 #include "lldb/Host/ProcessLauncher.h"
 #include "lldb/Host/ThreadLauncher.h"
 #include "lldb/Host/posix/ConnectionFileDescriptorPosix.h"
+#include "lldb/Utility/Args.h"
 #include "lldb/Utility/FileSpec.h"
 #include "lldb/Utility/LLDBLog.h"
 #include "lldb/Utility/Log.h"
@@ -56,9 +58,11 @@
 #include "lldb/Utility/Status.h"
 #include "lldb/lldb-private-forward.h"
 #include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX
 #include "llvm/Support/Errno.h"
 #include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Program.h"
 
 #if defined(_WIN32)
 #include "lldb/Host/windows/ConnectionGenericFileWindows.h"
@@ -612,8 +616,60 @@ llvm::Error Host::OpenFileInExternalEditor(llvm::StringRef 
editor,
 }
 
 bool Host::IsInteractiveGraphicSession() { return false; }
+
+llvm::Error Host::OpenURL(llvm::StringRef url) {
+  if (url.empty())
+    return llvm::createStringError("cannot open empty URL");
+
+  LLDB_LOG(GetLog(LLDBLog::Host), "Opening URL: {0}", url);
+
+#if defined(_WIN32)
+  // TODO: open the URL with ShellExecuteW (needs a shell32 link dependency).
+  return llvm::errorCodeToError(
+      std::error_code(ENOTSUP, std::system_category()));
+#else
+  // Resolve xdg-open and run it directly (run_in_shell=false) so the URL is a
+  // literal argument the shell never parses; this keeps query-string
+  // metacharacters from being interpreted regardless of the user's shell.
+  llvm::ErrorOr<std::string> xdg_open =
+      llvm::sys::findProgramByName("xdg-open");
+  if (!xdg_open)
+    return llvm::createStringError("could not find xdg-open to open the URL");
+
+  Args args;
+  args.AppendArgument(*xdg_open);
+  args.AppendArgument(url);
+
+  int status = 0;
+  int signo = 0;
+  std::string output;
+  Status error = RunShellCommand(
+      args, /*working_dir=*/FileSpec(), &status, &signo, &output,
+      /*separated_error_output=*/nullptr, std::chrono::seconds(10),
+      /*run_in_shell=*/false);
+  if (error.Fail())
+    return error.takeError();
+  if (status != 0)
+    return llvm::createStringError(
+        llvm::formatv("xdg-open exited with status {0}", status));
+  return llvm::Error::success();
+#endif
+}
 #endif
 
+std::string Host::URLEncode(llvm::StringRef str) {
+  std::string out;
+  llvm::raw_string_ostream os(out);
+  for (unsigned char c : str) {
+    if (std::isalnum(c) || llvm::StringRef("-_.~").contains(c))
+      os << c;
+    else
+      os << '%' << llvm::hexdigit((c >> 4) & 0xF, /*LowerCase=*/false)
+         << llvm::hexdigit(c & 0xF, /*LowerCase=*/false);
+  }
+  return out;
+}
+
 std::unique_ptr<Connection> Host::CreateDefaultConnection(llvm::StringRef url) 
{
 #if defined(_WIN32)
   if (url.starts_with("file://"))
diff --git a/lldb/unittests/Host/HostTest.cpp b/lldb/unittests/Host/HostTest.cpp
index f55b78cb923ff..a2d20a3822cd6 100644
--- a/lldb/unittests/Host/HostTest.cpp
+++ b/lldb/unittests/Host/HostTest.cpp
@@ -168,3 +168,14 @@ TEST(Host, LaunchProcessDuplicatesHandle) {
   ASSERT_THAT_EXPECTED(bytes_read, llvm::Succeeded());
   ASSERT_EQ(llvm::StringRef(msg, *bytes_read), test_msg);
 }
+
+TEST(Host, URLEncode) {
+  // Unreserved characters (RFC 3986) are kept literal.
+  EXPECT_EQ(Host::URLEncode("AZaz09-_.~"), "AZaz09-_.~");
+  // Everything else, including query-string metacharacters, is 
percent-encoded.
+  EXPECT_EQ(Host::URLEncode("a b&c=d"), "a%20b%26c%3Dd");
+  EXPECT_EQ(Host::URLEncode("/?#"), "%2F%3F%23");
+  // High bytes are encoded as two upper-case hex digits.
+  EXPECT_EQ(Host::URLEncode("\xC3\xA9"), "%C3%A9");
+  EXPECT_EQ(Host::URLEncode(""), "");
+}

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to