1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-03-03 14:52:21 +02:00

Fix escaping in JSON string parser.

This commit is contained in:
David Steele 2019-01-19 12:57:40 +02:00
parent 7355248d6b
commit e57f1b5293
4 changed files with 69 additions and 20 deletions

View File

@ -66,7 +66,7 @@
</release-item>
<release-item>
<p>JSON improvements. Allow empty arrays in JSON parser. Fix null output in JSON renderer. Fix escaping in JSON string renderer.</p>
<p>JSON improvements. Allow empty arrays in JSON parser. Fix null output in JSON renderer. Fix escaping in JSON string parser/renderer.</p>
</release-item>
<release-item>

View File

@ -11,31 +11,77 @@ Convert JSON to/from KeyValue
Given a character array and its size, return a variant from the extracted string
***********************************************************************************************************************************/
static Variant *
jsonString(const char *jsonC, size_t strSize, unsigned int *jsonPos, unsigned int *valueBeginPos)
jsonString(const char *jsonC, unsigned int *jsonPos)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(CHARPY, jsonC);
FUNCTION_TEST_PARAM(SIZE, strSize);
FUNCTION_TEST_PARAM(UINTP, jsonPos);
FUNCTION_TEST_PARAM(UINTP, valueBeginPos);
FUNCTION_TEST_END();
Variant *result = NULL;
MEM_CONTEXT_TEMP_BEGIN()
{
*valueBeginPos = *valueBeginPos + 1;
*jsonPos = *jsonPos + 1;
// Find the end of the string within the entire character array
while (jsonC[*jsonPos] != '"' && *jsonPos < strSize - 1)
String *resultStr = strNew("");
while (jsonC[*jsonPos] != '"')
{
if (jsonC[*jsonPos] == '\\')
{
*jsonPos = *jsonPos + 1;
switch (jsonC[*jsonPos])
{
case '"':
strCatChr(resultStr, '"');
break;
case '\\':
strCatChr(resultStr, '\\');
break;
case '/':
strCatChr(resultStr, '/');
break;
case 'n':
strCatChr(resultStr, '\n');
break;
case 'r':
strCatChr(resultStr, '\r');
break;
case 't':
strCatChr(resultStr, '\t');
break;
case 'b':
strCatChr(resultStr, '\b');
break;
case 'f':
strCatChr(resultStr, '\f');
break;
default:
THROW_FMT(JsonFormatError, "invalid escape character '%c'", jsonC[*jsonPos]);
}
}
else
{
if (jsonC[*jsonPos] == '\0')
THROW(JsonFormatError, "expected '\"' but found null delimiter");
strCatChr(resultStr, jsonC[*jsonPos]);
}
*jsonPos = *jsonPos + 1;
};
if (jsonC[*jsonPos] != '"')
THROW_FMT(JsonFormatError, "expected '\"' but found '%c'", jsonC[*jsonPos]);
// Extract the string, including the enclosing quotes and return it as a variant
String *resultStr = strNewN(jsonC + *valueBeginPos, *jsonPos - *valueBeginPos);
// Create a variant result for the string
memContextSwitch(MEM_CONTEXT_OLD());
result = varNewStr(resultStr);
memContextSwitch(MEM_CONTEXT_TEMP());
@ -144,14 +190,11 @@ jsonToKv(const String *json)
// The value appears to be a string
if (jsonC[jsonPos] == '"')
{
value = jsonString(jsonC, strSize(json), &jsonPos, &valueBeginPos);
value = jsonString(jsonC, &jsonPos);
}
// The value appears to be a number
else if (isdigit(jsonC[jsonPos]))
{
value = jsonNumeric(jsonC, strSize(json), &jsonPos, &valueBeginPos);
}
// The value appears to be a boolean
else if (jsonC[jsonPos] == 't' || jsonC[jsonPos] == 'f')
@ -204,7 +247,7 @@ jsonToKv(const String *json)
arrayType = 's';
value = jsonString(jsonC, strSize(json), &jsonPos, &valueBeginPos);
value = jsonString(jsonC, &jsonPos);
}
// The value appears to be a number

View File

@ -26,7 +26,7 @@ testRun(void)
JsonFormatError, "expected '}' but found 'h'");
TEST_ERROR(jsonToKv(strNew("{\"key1\":123")), JsonFormatError, "expected '}' but found '3'");
TEST_ERROR(jsonToKv(strNew("{\"key1\":123>")), JsonFormatError, "expected '}' but found '>'");
TEST_ERROR(jsonToKv(strNew("{\"key1\":\"123'}")), JsonFormatError, "expected '\"' but found '}'");
TEST_ERROR(jsonToKv(strNew("{\"key1\":\"123'}")), JsonFormatError, "expected '\"' but found null delimiter");
TEST_ERROR(jsonToKv(strNew("{\"key1\":[\"\",]}")), JsonFormatError, "unknown array value type");
TEST_ERROR(jsonToKv(strNew("{\"key1\":[\"\",1]}")), JsonFormatError, "number found in array of type 's'");
TEST_ERROR(jsonToKv(strNew("{\"key1\":[1,\"\"]}")), JsonFormatError, "string found in array of type 'n'");
@ -37,6 +37,7 @@ testRun(void)
TEST_ERROR(jsonToKv(strNew("{\"key1\":nult")), JsonFormatError, "null delimit not found");
TEST_ERROR(jsonToKv(strNew("{\"key1\":noll")), JsonFormatError, "expected 'null' but found 'noll'");
TEST_ERROR(jsonToKv(strNew("{\"key1\":nully}")), JsonFormatError, "expected '}' but found 'y'");
TEST_ERROR(jsonToKv(strNew("{\"key1\":\"\\j\"}")), JsonFormatError, "invalid escape character 'j'");
// -------------------------------------------------------------------------------------------------------------------------
KeyValue *kv = NULL;
@ -47,6 +48,9 @@ testRun(void)
TEST_ASSIGN(kv, jsonToKv(strNew("{\"key1\":\"value1\"}")), "single string value");
TEST_RESULT_STR(strPtr(varStr(kvGet(kv, varNewStr(strNew("key1"))))), "value1", " check string");
TEST_ASSIGN(kv, jsonToKv(strNew("{\"key1\":\"\\\"\\\\\\/\\b\\n\\r\\t\\f\"}")), "single string value with escapes");
TEST_RESULT_STR(strPtr(varStr(kvGet(kv, varNewStr(strNew("key1"))))), "\"\\/\b\n\r\t\f", " check string");
TEST_ASSIGN(kv, jsonToKv(strNew("{\"key1\":true}")), "boolean true");
TEST_RESULT_BOOL(varBool(kvGet(kv, varNewStr(strNew("key1")))), true, " check boolean");

View File

@ -42,8 +42,10 @@ testRun(void)
storagePathCreateNP(storageTest, strNew("repo/testy"));
TEST_RESULT_STR(strPtr(strLstJoin(storageListNP(storageRemote, NULL), ",")), "testy" , "list path");
storagePathCreateNP(storageTest, strNew("repo/testy2"));
TEST_RESULT_STR(strPtr(strLstJoin(storageListNP(storageRemote, NULL), ",")), "testy,testy2" , "list 2 paths");
storagePathCreateNP(storageTest, strNew("repo/testy2\""));
TEST_RESULT_STR(
strPtr(strLstJoin(storageListNP(storageRemote, strNewFmt("%s/repo", testPath())), ",")), "testy,testy2\"" ,
"list 2 paths");
// -------------------------------------------------------------------------------------------------------------------------
Buffer *contentBuf = bufNew(32768);