[Lldb-commits] [lldb] dbd4528 - [lldb] Add a non-Darwin Host::OpenURL and a Host::URLEncode helper (#206129)
via lldb-commits
lldb-commits at lists.llvm.org
Fri Jun 26 10:15:23 PDT 2026
Author: Jonas Devlieghere
Date: 2026-06-26T10:15:17-07:00
New Revision: dbd4528e8d0f6c90d8896ae48e1f0505e83a0fc6
URL: https://github.com/llvm/llvm-project/commit/dbd4528e8d0f6c90d8896ae48e1f0505e83a0fc6
DIFF: https://github.com/llvm/llvm-project/commit/dbd4528e8d0f6c90d8896ae48e1f0505e83a0fc6.diff
LOG: [lldb] Add a non-Darwin Host::OpenURL and a Host::URLEncode helper (#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.
Added:
Modified:
lldb/include/lldb/Host/Host.h
lldb/source/Host/common/Host.cpp
lldb/unittests/Host/HostTest.cpp
Removed:
################################################################################
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(""), "");
+}
More information about the lldb-commits
mailing list