// Copyright Epic Games, Inc. All Rights Reserved. #include "browser_launcher.h" #include #include #include #include #include #if ZEN_PLATFORM_WINDOWS # include # include #else # include # include extern char** environ; #endif namespace zen { void LaunchBrowser(std::string_view Url) { if (Url.empty()) { throw zen::runtime_error("Cannot launch browser with empty URL"); } bool Success = false; #if ZEN_PLATFORM_WINDOWS std::string UrlZ(Url); HINSTANCE Result = ShellExecuteA(nullptr, "open", UrlZ.c_str(), nullptr, nullptr, SW_SHOWNORMAL); Success = reinterpret_cast(Result) > 32; #else # if ZEN_PLATFORM_MAC const char* Program = "open"; # elif ZEN_PLATFORM_LINUX const char* Program = "xdg-open"; # else ZEN_NOT_IMPLEMENTED("Browser launching not implemented on this platform"); const char* Program = nullptr; # endif // Spawn directly via posix_spawnp to avoid the shell entirely, so URL contents // cannot be interpreted as shell syntax regardless of what characters they contain. std::string Url_c(Url); char* const Argv[] = {const_cast(Program), Url_c.data(), nullptr}; pid_t Pid = 0; const int SpawnRc = posix_spawnp(&Pid, Program, nullptr, nullptr, Argv, environ); if (SpawnRc == 0) { int Status = 0; if (waitpid(Pid, &Status, 0) == Pid) { Success = WIFEXITED(Status) && WEXITSTATUS(Status) == 0; } } #endif if (!Success) { throw zen::runtime_error("Failed to launch browser for '{}'", Url); } ZEN_CONSOLE("Web browser launched for '{}' successfully", Url); } } // namespace zen