freerdp/SOURCES/winpr-crt-add-functions-to-test-string.patch
2026-08-13 05:19:41 -04:00

267 lines
7.2 KiB
Diff

From a7a47bc0bdab723b674fb05f51e93ae007ed6412 Mon Sep 17 00:00:00 2001
From: Armin Novak <armin.novak@thincast.com>
Date: Thu, 9 Jul 2026 08:34:23 +0200
Subject: [PATCH] [winpr,crt] add functions to test string
* winpr_str_has_newlines to check for newlines in a string
* winpr_str_is_valid_url and winpr_str_is_valid_urlN to check if a
string is a valid url
---
winpr/include/winpr/string.h | 5 ++
winpr/libwinpr/crt/CMakeLists.txt | 8 +++
winpr/libwinpr/crt/string.c | 96 ++++++++++++++++++++++++++++
winpr/libwinpr/crt/test/TestString.c | 82 ++++++++++++++++++++++++
4 files changed, 191 insertions(+)
diff --git a/winpr/include/winpr/string.h b/winpr/include/winpr/string.h
index bb98dffdc..7de9f934f 100644
--- a/winpr/include/winpr/string.h
+++ b/winpr/include/winpr/string.h
@@ -31,6 +31,11 @@ extern "C"
{
#endif
+ WINPR_API BOOL winpr_str_is_valid_url(const char* str);
+ WINPR_API BOOL winpr_str_is_valid_urlN(const char* str, size_t len);
+ WINPR_API BOOL winpr_str_has_newlines(const char* str);
+
+
WINPR_API BOOL winpr_str_append(const char* what, char* buffer, size_t size,
const char* separator);
diff --git a/winpr/libwinpr/crt/CMakeLists.txt b/winpr/libwinpr/crt/CMakeLists.txt
index 5ee4bbd1e..538e74dcf 100644
--- a/winpr/libwinpr/crt/CMakeLists.txt
+++ b/winpr/libwinpr/crt/CMakeLists.txt
@@ -22,6 +22,14 @@ set (CRT_FILES alignment.c
unicode.c
string.c)
+include(CheckSymbolExists)
+check_symbol_exists(regcomp regex.h WINPR_HAVE_REGCOMP)
+check_symbol_exists(regexec regex.h WINPR_HAVE_REGEXEC)
+check_symbol_exists(regfree regex.h WINPR_HAVE_REGFREE)
+if(WINPR_HAVE_REGCOMP AND WINPR_HAVE_REGEXEC AND WINPR_HAVE_REGFREE)
+ winpr_definition_add(-DWINPR_HAVE_REGCOMP)
+endif()
+
if (NOT WITH_ICU)
set (CRT_FILES ${CRT_FILES}
utf.c
diff --git a/winpr/libwinpr/crt/string.c b/winpr/libwinpr/crt/string.c
index 6596b42f5..465b8d133 100644
--- a/winpr/libwinpr/crt/string.c
+++ b/winpr/libwinpr/crt/string.c
@@ -29,11 +29,71 @@
#include <winpr/assert.h>
#include <winpr/endian.h>
+#if defined(WINPR_HAVE_REGCOMP)
+#include <regex.h>
+#endif
+
/* String Manipulation (CRT): http://msdn.microsoft.com/en-us/library/f0151s4x.aspx */
#include "../log.h"
#define TAG WINPR_TAG("crt")
+BOOL winpr_str_is_valid_urlN(const char* str, size_t len)
+{
+ if (!str || (len == 0))
+ return FALSE;
+
+ char* url = strndup(str, len);
+ if (!url)
+ return FALSE;
+
+ const BOOL rc = winpr_str_is_valid_url(url);
+ free(url);
+ return rc;
+}
+
+#if defined(_WIN32)
+#include <shlwapi.h>
+
+BOOL winpr_str_is_valid_url(const char* str)
+{
+ if (!str)
+ return FALSE;
+ return PathIsURLA(str);
+}
+
+#elif defined(WINPR_HAVE_REGCOMP)
+BOOL winpr_str_is_valid_url(const char* str)
+{
+ regex_t regex;
+ const char pattern[] = "^([a-z]+://)?([a-zA-Z0-9.-]+)(:[0-9]+)?(/[a-zA-Z0-9./?=&%-]*)?$";
+ int ret;
+
+ if (!str)
+ return FALSE;
+ memset(&regex, 0, sizeof(regex));
+
+ ret = regcomp(&regex, pattern, REG_EXTENDED);
+ if (ret)
+ {
+ printf("Could not compile regex\n");
+ return FALSE;
+ }
+
+ ret = regexec(&regex, str, 0, NULL, 0);
+ regfree(&regex);
+ return ret == 0;
+}
+
+#else
+BOOL winpr_str_is_valid_url(const char* str)
+{
+ WINPR_UNUSED(str);
+ WLog_WARN(TAG, "URL validation not supported by your build, not performing check.");
+ return TRUE;
+}
+#endif
+
BOOL winpr_str_append(const char* what, char* buffer, size_t size, const char* separator)
{
const size_t used = strnlen(buffer, size);
@@ -636,3 +696,39 @@ INT64 GetLine(char** lineptr, size_t* size, FILE* stream)
return -1;
#endif
}
+
+BOOL winpr_str_has_newlines(const char* str)
+{
+ if (!str)
+ return FALSE;
+ do
+ {
+ char c = *str++;
+ switch (c)
+ {
+ case '\r':
+ case '\n':
+ case 0x0b: /* VT vertical tab */
+ case 0x0c: /* FF form feed */
+ case (char)0x85: /* NEL next line */
+ return TRUE;
+ case 0x20:
+ {
+ switch (*str)
+ {
+ case 0x28: /* LS line separator */
+ case 0x29: /* PS paragraph separator */
+ return TRUE;
+ default:
+ break;
+ }
+ }
+ break;
+
+ case '\0':
+ return FALSE;
+ default:
+ break;
+ }
+ } while (1);
+}
diff --git a/winpr/libwinpr/crt/test/TestString.c b/winpr/libwinpr/crt/test/TestString.c
index df154fe1c..bca470bdd 100644
--- a/winpr/libwinpr/crt/test/TestString.c
+++ b/winpr/libwinpr/crt/test/TestString.c
@@ -27,6 +27,79 @@ static WCHAR testDelimiter[] = { '\r', '\n', '\0' };
#define testDelimiter_Length ((sizeof(testDelimiter) / sizeof(WCHAR)) - 1)
+static BOOL test_valid_url(void)
+{
+ struct test_t
+ {
+ char* string;
+ size_t len;
+ BOOL isUrl;
+ };
+
+ static const struct test_t tests[] = { { "foo.bar.blabla", 15, TRUE },
+ { "somehostname", 12, TRUE },
+ { "somehostname:1234", 17, TRUE },
+ { "tsv://somehostname", 18, TRUE },
+ { "tsv://somehostname/path/foo/gaga", 32, TRUE },
+ { "tsv://somehostname:1234", 23, TRUE },
+ { "tsv://somehostname:1234/path/foo", 33, TRUE },
+ { "lala\rgaga\n", 12, FALSE },
+ { "192.168.0.1", 11, TRUE },
+ //{ "192.168.0.1:1234", 16, FALSE },
+ //{ "192.168.0.1:1234/foo/", 21, FALSE },
+ { "192.168.0.1/bar/foo/", 20, TRUE },
+ { "[::1]", 5, FALSE },
+ { "[::1]:1234", 8, FALSE },
+ { "[2001:db8:3333:4444:5555:6666:7777:8888]", 40,
+ FALSE },
+ { "[2001:db8::1]", 13, FALSE } };
+ BOOL rc = TRUE;
+ for (size_t x = 0; x < ARRAYSIZE(tests); x++)
+ {
+ const struct test_t* cur = &tests[x];
+
+ const BOOL rc1 = winpr_str_is_valid_url(cur->string);
+ const BOOL rc2 = winpr_str_is_valid_urlN(cur->string, cur->len);
+
+#if defined(WINPR_HAVE_REGCOMP) || defined(WITH_URIPARSER)
+ if (rc1 != rc2)
+ rc = FALSE;
+ if (rc1 != cur->isUrl)
+ rc = FALSE;
+#else
+ fprintf(stderr, "[%s] TODO: !defined(WINPR_HAVE_REGCOMP) && !defined(WITH_URIPARSER)\n",
+ __func__);
+#endif
+ }
+
+ return rc;
+}
+
+static BOOL test_newline(void)
+{
+ struct test_t
+ {
+ char* string;
+ size_t len;
+ BOOL hasNewlines;
+ };
+
+ const struct test_t tests[] = { { "foo.bar.blabla", 15, FALSE },
+ { "somehostname", 12, FALSE },
+ { "lala\rgaga\n", 13, TRUE } };
+
+ for (size_t x = 0; x < ARRAYSIZE(tests); x++)
+ {
+ const struct test_t* cur = &tests[x];
+
+ const BOOL rc1 = winpr_str_has_newlines(cur->string);
+ if (rc1 != cur->hasNewlines)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
int TestString(int argc, char* argv[])
{
WCHAR* p;
@@ -34,6 +107,15 @@ int TestString(int argc, char* argv[])
size_t length;
WCHAR* context;
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+
+ if (!test_valid_url())
+ return -1;
+
+ if (!test_newline())
+ return -1;
+
#ifdef __BIG_ENDIAN__
/* Be sure that we always use LE encoded string */
ByteSwapUnicode(testStringW, testStringW_Length);