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
