mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-03-05 15:05:48 +02:00
Fix escaping in JSON string parser.
This commit is contained in:
parent
7355248d6b
commit
e57f1b5293
@ -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>
|
||||
|
@ -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;
|
||||
|
||||
if (jsonC[*jsonPos] != '"')
|
||||
THROW_FMT(JsonFormatError, "expected '\"' but found '%c'", jsonC[*jsonPos]);
|
||||
switch (jsonC[*jsonPos])
|
||||
{
|
||||
case '"':
|
||||
strCatChr(resultStr, '"');
|
||||
break;
|
||||
|
||||
// Extract the string, including the enclosing quotes and return it as a variant
|
||||
String *resultStr = strNewN(jsonC + *valueBeginPos, *jsonPos - *valueBeginPos);
|
||||
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;
|
||||
};
|
||||
|
||||
// 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
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user