Skip to content

Commit ee4c92f

Browse files
committed
fix: control URL length on Wine Linux/MacOS
The de facto limit for URL lengths under Wine on Linux seems to be somewhere around 1500 bytes, refuse to open the URL and return a reason as a string through the Lua API call.
1 parent dcb360d commit ee4c92f

File tree

6 files changed

+51
-38
lines changed

6 files changed

+51
-38
lines changed

engine/system/sys_main.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ class find_c {
4949
std::filesystem::directory_iterator iter;
5050
};
5151

52+
std::string GetWineHostVersion();
53+
5254
// ==========
5355
// Interfaces
5456
// ==========
@@ -75,7 +77,7 @@ class sys_IMain {
7577
virtual char* ClipboardPaste() = 0;
7678
virtual bool SetWorkDir(const char* newCwd = NULL) = 0;
7779
virtual void SpawnProcess(const char* cmdName, const char* argList) = 0;
78-
virtual void OpenURL(const char* url) = 0;
80+
virtual std::optional<std::string> OpenURL(const char* url) = 0;
7981
virtual void Error(const char* fmt, ...) = 0;
8082
virtual void Exit(const char* msg = NULL) = 0;
8183
virtual void Restart() = 0;

engine/system/win/sys_local.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class sys_main_c: public sys_IMain {
3737
char* ClipboardPaste();
3838
bool SetWorkDir(const char* newCwd = NULL);
3939
void SpawnProcess(const char* cmdName, const char* argList);
40-
void OpenURL(const char* url);
40+
std::optional<std::string> OpenURL(const char* url); // return value has failure reason
4141
void Error(const char* fmt, ...);
4242
void Exit(const char* msg = NULL);
4343
void Restart();

engine/system/win/sys_macos.mm

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
#include <CoreFoundation/CFBundle.h>
33
#include <ApplicationServices/ApplicationServices.h>
44

5-
void PlatformOpenURL(const char* textUrl)
5+
const char* PlatformOpenURL(const char* textUrl)
66
{
77
std::string_view urlView = textUrl;
88
CFURLRef url = CFURLCreateWithBytes(nullptr, (const UInt8*)urlView.data(), urlView.size(), kCFStringEncodingUTF8, nullptr);
99
LSOpenCFURLRef(url, nullptr);
1010
CFRelease(url);
11+
return nullptr;
1112
}

engine/system/win/sys_main.cpp

+40-12
Original file line numberDiff line numberDiff line change
@@ -408,30 +408,58 @@ void sys_main_c::SpawnProcess(const char* cmdName, const char* argList)
408408
#endif
409409
}
410410

411+
std::string GetWineHostVersion()
412+
{
413+
#ifdef _WIN32
414+
using WineHostVersionFun = void(const char** /*sysname*/, const char** /*release*/);
415+
HMODULE mod = GetModuleHandleA("ntdll.dll");
416+
if (!mod)
417+
return "";
418+
auto ptr = GetProcAddress(mod, "wine_get_host_version");
419+
if (!ptr)
420+
return "";
421+
auto fun = (WineHostVersionFun*)ptr;
422+
const char* sysname{};
423+
const char* release{};
424+
fun(&sysname, &release);
425+
return sysname ? sysname : "";
426+
#else
427+
return "";
428+
#endif
429+
}
430+
411431
#if _WIN32 || __linux__
412-
void PlatformOpenURL(const char* url)
432+
const char* PlatformOpenURL(const char* url)
413433
{
414434
#ifdef _WIN32
415-
// There is a surprisingly low limit for the maximum URL length that ShellExecute and browsers can open.
416-
// A common lower limit on Windows is 2083, so we'll definitely refuse to open URLs longer than that.
417-
// Wine on Linux has an indeterminate boundary above which it either crashes or silently does nothing,
418-
// one one system it landed at around 1575 bytes before failure, so put the limit somewhat below that.
419-
if (strlen(url) <= 1500)
420-
{
421-
ShellExecuteA(NULL, "open", url, NULL, NULL, SW_SHOWDEFAULT);
422-
}
435+
const std::string wineHost = GetWineHostVersion();
436+
/*
437+
Wine has some loosely determined maximum length on how long of an URL
438+
can be, so we pick a "safe" maximum and refuse to open anything longer.
439+
*/
440+
if ((wineHost == "Linux" || wineHost == "Darwin") && strlen(url) > 1500)
441+
return AllocString("Did not open URL, length likely too long for the OS.");
442+
ShellExecuteA(NULL, "open", url, NULL, NULL, SW_SHOWDEFAULT);
443+
return nullptr;
423444
#else
424445
#warning LV: URL opening not implemented on this OS.
425446
// TODO(LV): Implement URL opening for other OSes.
447+
return AllocString("URL opening not implemented on this OS.");
426448
#endif
427449
}
428450
#else
429-
void PlatformOpenURL(const char* url);
451+
const char* PlatformOpenURL(const char* url);
430452
#endif
431453

432-
void sys_main_c::OpenURL(const char* url)
454+
std::optional<std::string> sys_main_c::OpenURL(const char* url)
433455
{
434-
PlatformOpenURL(url);
456+
if (auto err = PlatformOpenURL(url))
457+
{
458+
std::string ret = err;
459+
FreeString(err);
460+
return ret;
461+
}
462+
return {};
435463
}
436464

437465
// ==============================

engine/system/win/sys_video.cpp

-21
Original file line numberDiff line numberDiff line change
@@ -98,27 +98,6 @@ void sys_IVideo::FreeHandle(sys_IVideo* hnd)
9898
delete (sys_video_c*)hnd;
9999
}
100100

101-
102-
static std::string GetWineHostVersion()
103-
{
104-
#ifdef _WIN32
105-
using WineHostVersionFun = void (const char** /*sysname*/, const char** /*release*/);
106-
HMODULE mod = GetModuleHandleA("ntdll.dll");
107-
if (!mod)
108-
return "";
109-
auto ptr = GetProcAddress(mod, "wine_get_host_version");
110-
if (!ptr)
111-
return "";
112-
auto fun = (WineHostVersionFun*)ptr;
113-
const char* sysname{};
114-
const char* release{};
115-
fun(&sysname, &release);
116-
return sysname ? sysname : "";
117-
#else
118-
return "";
119-
#endif
120-
}
121-
122101
sys_video_c::sys_video_c(sys_IMain* sysHnd)
123102
: sys((sys_main_c*)sysHnd)
124103
{

ui_api.cpp

+5-2
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@
100100
** ConPrintTable(table[, noRecurse])
101101
** ConExecute("<cmd>")
102102
** SpawnProcess("<cmdName>"[, "<args>"])
103-
** OpenURL("<url>")
103+
** err = OpenURL("<url>")
104104
** SetProfiling(isEnabled)
105105
** Restart()
106106
** Exit(["<message>"])
@@ -1869,7 +1869,10 @@ static int l_OpenURL(lua_State* L)
18691869
int n = lua_gettop(L);
18701870
ui->LAssert(L, n >= 1, "Usage: OpenURL(url)");
18711871
ui->LAssert(L, lua_isstring(L, 1), "OpenURL() argument 1: expected string, got %s", luaL_typename(L, 1));
1872-
ui->sys->OpenURL(lua_tostring(L, 1));
1872+
if (auto errMsg = ui->sys->OpenURL(lua_tostring(L, 1))) {
1873+
lua_pushstring(L, errMsg->c_str());
1874+
return 1;
1875+
}
18731876
return 0;
18741877
}
18751878

0 commit comments

Comments
 (0)