mirror of
https://github.com/morgan9e/FreeRDP
synced 2026-04-15 00:44:19 +09:00
[winpr,clipboard] fix url unescape for file uri
This commit is contained in:
@@ -1955,7 +1955,7 @@ static BOOL cliprdr_local_file_new(CliprdrFileContext* context, CliprdrLocalFile
|
||||
|
||||
*f = empty;
|
||||
f->context = context;
|
||||
f->name = _strdup(path);
|
||||
f->name = winpr_str_url_decode(path, strlen(path));
|
||||
if (!f->name)
|
||||
goto fail;
|
||||
|
||||
|
||||
@@ -33,6 +33,9 @@ extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
WINPR_API char* winpr_str_url_encode(const char* str, size_t len);
|
||||
WINPR_API char* winpr_str_url_decode(const char* str, size_t len);
|
||||
|
||||
WINPR_API BOOL winpr_str_append(const char* what, char* buffer, size_t size,
|
||||
const char* separator);
|
||||
|
||||
|
||||
@@ -726,10 +726,9 @@ char* parse_uri_to_local_file(const char* uri, size_t uri_len)
|
||||
|
||||
} while (0);
|
||||
|
||||
buffer = calloc(localLen + 1, sizeof(char));
|
||||
buffer = winpr_str_url_decode(localName, localLen);
|
||||
if (buffer)
|
||||
{
|
||||
memcpy(buffer, localName, localLen);
|
||||
if (buffer[1] == '|' &&
|
||||
((buffer[0] >= 'A' && buffer[0] <= 'Z') || (buffer[0] >= 'a' && buffer[0] <= 'z')))
|
||||
buffer[1] = ':';
|
||||
|
||||
@@ -39,6 +39,92 @@
|
||||
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
|
||||
#endif
|
||||
|
||||
static const char rfc3986[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x2e, 0x00,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x5f,
|
||||
0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x00, 0x00, 0x00, 0x7e, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
static char hex2bin(char what)
|
||||
{
|
||||
if (what >= 'a')
|
||||
what -= 'a' - 'A';
|
||||
if (what >= 'A')
|
||||
what -= ('A' - 10);
|
||||
else
|
||||
what -= '0';
|
||||
return what;
|
||||
}
|
||||
|
||||
static char unescape(const char* what, size_t* px)
|
||||
{
|
||||
if ((*what == '%') && (isxdigit(what[1]) && isxdigit(what[2])))
|
||||
{
|
||||
*px += 2;
|
||||
return 16 * hex2bin(what[1]) + hex2bin(what[2]);
|
||||
}
|
||||
|
||||
if (*what == '+')
|
||||
return ' ';
|
||||
|
||||
return *what;
|
||||
}
|
||||
|
||||
char* winpr_str_url_decode(const char* str, size_t len)
|
||||
{
|
||||
char* dst = calloc(len + 1, sizeof(char));
|
||||
if (!dst)
|
||||
return NULL;
|
||||
|
||||
size_t pos = 0;
|
||||
for (size_t x = 0; x < strnlen(str, len); x++)
|
||||
{
|
||||
const char* cur = &str[x];
|
||||
dst[pos++] = unescape(cur, &x);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
static char* escape(char* dst, char what)
|
||||
{
|
||||
if (rfc3986[what & 0xff])
|
||||
{
|
||||
*dst = what;
|
||||
return dst + 1;
|
||||
}
|
||||
|
||||
sprintf(dst, "%%%02" PRIX8, what & 0xff);
|
||||
return dst + 3;
|
||||
}
|
||||
|
||||
char* winpr_str_url_encode(const char* str, size_t len)
|
||||
{
|
||||
char* dst = calloc(len + 1, sizeof(char) * 3);
|
||||
if (!dst)
|
||||
return NULL;
|
||||
|
||||
char* ptr = dst;
|
||||
for (size_t x = 0; x < strnlen(str, len); x++)
|
||||
{
|
||||
const char cur = str[x];
|
||||
ptr = escape(ptr, cur);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
BOOL winpr_str_append(const char* what, char* buffer, size_t size, const char* separator)
|
||||
{
|
||||
const size_t used = strnlen(buffer, size);
|
||||
|
||||
@@ -27,6 +27,56 @@ static WCHAR testDelimiter[] = { '\r', '\n', '\0' };
|
||||
|
||||
#define testDelimiter_Length ((sizeof(testDelimiter) / sizeof(WCHAR)) - 1)
|
||||
|
||||
struct url_test_pair
|
||||
{
|
||||
const char* what;
|
||||
const char* escaped;
|
||||
};
|
||||
|
||||
static const struct url_test_pair url_tests[] = {
|
||||
{ "xxx%bar ga<ka>ee#%%#%{h}g{f{e%d|c\\b^a~p[q]r`s;t/u?v:w@x=y&z$xxx",
|
||||
"xxx%25bar%20ga%3Cka%3Eee%23%25%25%23%25%7Bh%7Dg%7Bf%7Be%25d%7Cc%5Cb%5Ea~p%5Bq%5Dr%60s%3Bt%"
|
||||
"2Fu%3Fv%3Aw%40x%3Dy%26z%24xxx" },
|
||||
{ "äöúëü", "%C3%A4%C3%B6%C3%BA%C3%AB%C3%BC" },
|
||||
{ "🎅🏄🤘😈", "%F0%9F%8E%85%F0%9F%8F%84%F0%9F%A4%98%F0%9F%98%88" }
|
||||
};
|
||||
|
||||
static BOOL test_url_escape(void)
|
||||
{
|
||||
for (size_t x = 0; x < ARRAYSIZE(url_tests); x++)
|
||||
{
|
||||
const struct url_test_pair* cur = &url_tests[x];
|
||||
|
||||
char* escaped = winpr_str_url_encode(cur->what, strlen(cur->what) + 1);
|
||||
char* what = winpr_str_url_decode(cur->escaped, strlen(cur->escaped) + 1);
|
||||
|
||||
const size_t elen = strlen(escaped);
|
||||
const size_t wlen = strlen(what);
|
||||
const size_t pelen = strlen(cur->escaped);
|
||||
const size_t pwlen = strlen(cur->what);
|
||||
BOOL rc = TRUE;
|
||||
if (!escaped || (elen != pelen) || (strcmp(escaped, cur->escaped) != 0))
|
||||
{
|
||||
printf("expected: [%" PRIuz "] %s\n", pelen, cur->escaped);
|
||||
printf("got : [%" PRIuz "] %s\n", elen, escaped);
|
||||
rc = FALSE;
|
||||
}
|
||||
else if (!what || (wlen != pwlen) || (strcmp(what, cur->what) != 0))
|
||||
{
|
||||
printf("expected: [%" PRIuz "] %s\n", pwlen, cur->what);
|
||||
printf("got : [%" PRIuz "] %s\n", wlen, what);
|
||||
rc = FALSE;
|
||||
}
|
||||
|
||||
free(escaped);
|
||||
free(what);
|
||||
if (!rc)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int TestString(int argc, char* argv[])
|
||||
{
|
||||
const WCHAR* p;
|
||||
@@ -37,6 +87,9 @@ int TestString(int argc, char* argv[])
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
if (!test_url_escape())
|
||||
return -1;
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
/* Be sure that we always use LE encoded string */
|
||||
ByteSwapUnicode(testStringW, testStringW_Length);
|
||||
|
||||
Reference in New Issue
Block a user