MDEV-7533: COLUMN_JSON() doesn't escape control characters in string values

escape all charecters less or equal 0x1F (control symbols)
(shorter sequence are not used to make code simple, long encoding is always legal according to the rfc4627)
This commit is contained in:
Oleksandr Byelkin 2018-01-22 16:53:10 +01:00
parent ea78c5744b
commit a4663af05c
4 changed files with 79 additions and 2 deletions

View File

@ -69,6 +69,9 @@ typedef struct st_mysql_lex_string LEX_STRING;
#define DYNCOL_UTF (&my_charset_utf8_general_ci)
#endif
/* escape json strings */
#define DYNCOL_JSON_ESC ((char)1)
enum enum_dyncol_func_result
{
ER_DYNCOL_OK= 0,

View File

@ -1873,5 +1873,15 @@ SELECT COLUMN_JSON(COLUMN_CREATE('a',1 AS DECIMAL,'b',1 AS DECIMAL));
COLUMN_JSON(COLUMN_CREATE('a',1 AS DECIMAL,'b',1 AS DECIMAL))
{"a":1,"b":1}
#
# MDEV-7533: COLUMN_JSON() doesn't escape control characters
# in string values
#
SELECT COLUMN_JSON(COLUMN_CREATE('test','"\\\t\n\Z')) AS json;
json
{"test":"\"\\\u0009\u000A\u001A"}
SELECT COLUMN_JSON(COLUMN_CREATE('test','First line\nSecond line')) AS json;
json
{"test":"First line\u000ASecond line"}
#
# end of 10.0 tests
#

View File

@ -920,6 +920,14 @@ SELECT COLUMN_JSON(COLUMN_CREATE('a',0 AS DECIMAL,'b',1 AS DECIMAL));
SELECT COLUMN_JSON(COLUMN_CREATE('a',1 AS DECIMAL,'b',1 AS DECIMAL));
--echo #
--echo # MDEV-7533: COLUMN_JSON() doesn't escape control characters
--echo # in string values
--echo #
SELECT COLUMN_JSON(COLUMN_CREATE('test','"\\\t\n\Z')) AS json;
SELECT COLUMN_JSON(COLUMN_CREATE('test','First line\nSecond line')) AS json;
--echo #
--echo # end of 10.0 tests
--echo #

View File

@ -3819,6 +3819,58 @@ end:
DBUG_RETURN(rc);
}
static
my_bool dynstr_append_json_quoted(DYNAMIC_STRING *str,
const char *append, size_t len)
{
uint additional= ((str->alloc_increment && str->alloc_increment > 6) ?
str->alloc_increment :
10);
uint lim= additional;
uint i;
if (dynstr_realloc(str, len + additional + 2))
return TRUE;
str->str[str->length++]= '"';
for (i= 0; i < len; i++)
{
register char c= append[i];
if (unlikely(c <= 0x1F))
{
if (lim < 5)
{
if (dynstr_realloc(str, additional))
return TRUE;
lim+= additional;
}
lim-= 5;
str->str[str->length++]= '\\';
str->str[str->length++]= 'u';
str->str[str->length++]= '0';
str->str[str->length++]= '0';
str->str[str->length++]= (c < 0x10 ? '0' : '1');
c%= 0x10;
str->str[str->length++]= (c < 0xA ? '0' + c : 'A' + (c - 0xA));
}
else
{
if (c == '"' || c == '\\')
{
if (!lim)
{
if (dynstr_realloc(str, additional))
return TRUE;
lim= additional;
}
lim--;
str->str[str->length++]= '\\';
}
str->str[str->length++]= c;
}
}
str->str[str->length++]= '"';
return FALSE;
}
enum enum_dyncol_func_result
mariadb_dyncol_val_str(DYNAMIC_STRING *str, DYNAMIC_COLUMN_VALUE *val,
@ -3884,7 +3936,10 @@ mariadb_dyncol_val_str(DYNAMIC_STRING *str, DYNAMIC_COLUMN_VALUE *val,
return ER_DYNCOL_RESOURCE;
}
if (quote)
rc= dynstr_append_quoted(str, from, len, quote);
if (quote == DYNCOL_JSON_ESC)
rc= dynstr_append_json_quoted(str, from, len);
else
rc= dynstr_append_quoted(str, from, len, quote);
else
rc= dynstr_append_mem(str, from, len);
if (alloc)
@ -4184,7 +4239,8 @@ mariadb_dyncol_json_internal(DYNAMIC_COLUMN *str, DYNAMIC_STRING *json,
}
else
{
if ((rc= mariadb_dyncol_val_str(json, &val, DYNCOL_UTF, '"')) < 0)
if ((rc= mariadb_dyncol_val_str(json, &val, DYNCOL_UTF, DYNCOL_JSON_ESC))
< 0)
goto err;
}
}