mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2024-12-12 10:04:14 +02:00
Fix non-compliant JSON for options passed from C to Perl.
We have been using a hacked-up JSON generator to pass options from C to Perl since the C binary was introduced. This generator was not very compliant which led to issues with \n, ", etc. inside strings. We have a fully-compliant JSON generator now so use that instead. Reported by Leo Khomenko.
This commit is contained in:
parent
70c30dfb61
commit
1f66bda02e
@ -30,6 +30,14 @@
|
||||
|
||||
<p>Fix info command missing WAL min/max when stanza specified.</p>
|
||||
</release-item>
|
||||
|
||||
<release-item>
|
||||
<release-item-contributor-list>
|
||||
<release-item-ideator id="leo.khomenko"/>
|
||||
</release-item-contributor-list>
|
||||
|
||||
<p>Fix non-compliant JSON for options passed from C to Perl.</p>
|
||||
</release-item>
|
||||
</release-bug-list>
|
||||
|
||||
<release-development-list>
|
||||
@ -6469,6 +6477,11 @@
|
||||
<contributor-id type="github">LaetitiaLoxo</contributor-id>
|
||||
</contributor>
|
||||
|
||||
<contributor id="leo.khomenko">
|
||||
<contributor-name-display>Leo Khomenko</contributor-name-display>
|
||||
<contributor-id type="github">lkhomenk</contributor-id>
|
||||
</contributor>
|
||||
|
||||
<contributor id="leonardo.gg.avellar">
|
||||
<contributor-name-display>Leonardo GG Avellar</contributor-name-display>
|
||||
<contributor-id type="github">L30Bola</contributor-id>
|
||||
|
@ -93,9 +93,6 @@ sub configLoad
|
||||
|
||||
eval
|
||||
{
|
||||
# Hacky fix for backslashes that need to be escaped
|
||||
$$rstrConfigJson =~ s/\\/\\\\/g;
|
||||
|
||||
%oOption = %{(JSON::PP->new()->allow_nonref())->decode($$rstrConfigJson)};
|
||||
return true;
|
||||
}
|
||||
|
@ -66,6 +66,7 @@ my @stryCFile =
|
||||
'common/time.c',
|
||||
'common/type/convert.c',
|
||||
'common/type/buffer.c',
|
||||
'common/type/json.c',
|
||||
'common/type/keyValue.c',
|
||||
'common/type/list.c',
|
||||
'common/type/string.c',
|
||||
|
@ -380,7 +380,7 @@ info/infoPg.o: info/infoPg.c common/assert.h common/debug.h common/error.auto.h
|
||||
main.o: main.c command/archive/get/get.h command/archive/push/push.h command/command.h command/help/help.h command/info/info.h command/remote/remote.h common/assert.h common/debug.h common/error.auto.h common/error.h common/exit.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h config/load.h perl/exec.h postgres/interface.h version.h
|
||||
$(CC) $(CFLAGS) -c main.c -o main.o
|
||||
|
||||
perl/config.o: perl/config.c common/assert.h common/debug.h common/error.auto.h common/error.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h
|
||||
perl/config.o: perl/config.c common/assert.h common/debug.h common/error.auto.h common/error.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/json.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h
|
||||
$(CC) $(CFLAGS) -c perl/config.c -o perl/config.o
|
||||
|
||||
perl/exec.o: perl/exec.c ../libc/LibC.h common/assert.h common/debug.h common/encode.h common/error.auto.h common/error.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h config/load.h config/parse.h crypto/cipherBlock.h crypto/crypto.h crypto/hash.h perl/config.h perl/embed.auto.c perl/exec.h perl/libc.auto.c postgres/pageChecksum.h storage/driver/posix/fileRead.h storage/driver/posix/fileWrite.h storage/driver/posix/storage.h storage/fileRead.h storage/fileWrite.h storage/info.h storage/storage.h storage/storage.intern.h version.h ../libc/xs/common/encode.xsh ../libc/xs/crypto/cipherBlock.xsh ../libc/xs/crypto/hash.xsh
|
||||
|
@ -3,6 +3,7 @@ Perl Configuration
|
||||
***********************************************************************************************************************************/
|
||||
#include "common/debug.h"
|
||||
#include "common/memContext.h"
|
||||
#include "common/type/json.h"
|
||||
#include "config/config.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
@ -13,56 +14,57 @@ perlOptionJson(void)
|
||||
{
|
||||
FUNCTION_TEST_VOID();
|
||||
|
||||
String *result = strNew("{");
|
||||
String *result = NULL;
|
||||
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
KeyValue *configKv = kvNew();
|
||||
|
||||
for (ConfigOption optionId = 0; optionId < CFG_OPTION_TOTAL; optionId++)
|
||||
{
|
||||
// Skip if not valid
|
||||
if (!cfgOptionValid(optionId))
|
||||
continue;
|
||||
|
||||
// Add comma if not first valid option
|
||||
if (strSize(result) != 1)
|
||||
strCat(result, ",");
|
||||
Variant *optionVar = varNewKv();
|
||||
|
||||
// Add valid and source
|
||||
strCatFmt(result, "\"%s\":{\"valid\":true,\"source\":\"", cfgOptionName(optionId));
|
||||
// Add valid
|
||||
kvPut(varKv(optionVar), varNewStr(strNew("valid")), varNewBool(true));
|
||||
|
||||
// Add source
|
||||
const char *source = NULL;
|
||||
|
||||
switch (cfgOptionSource(optionId))
|
||||
{
|
||||
case cfgSourceParam:
|
||||
{
|
||||
strCat(result, "param");
|
||||
source = "param";
|
||||
break;
|
||||
}
|
||||
|
||||
case cfgSourceConfig:
|
||||
{
|
||||
strCat(result, "config");
|
||||
source = "config";
|
||||
break;
|
||||
}
|
||||
|
||||
case cfgSourceDefault:
|
||||
{
|
||||
strCat(result, "default");
|
||||
source = "default";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
strCat(result, "\"");
|
||||
kvPut(varKv(optionVar), varNewStr(strNew("source")), varNewStr(strNew(source)));
|
||||
|
||||
// Add negate
|
||||
strCatFmt(result, ",\"negate\":%s", strPtr(varStrForce(varNewBool(cfgOptionNegate(optionId)))));
|
||||
|
||||
// Add reset
|
||||
strCatFmt(result, ",\"reset\":%s", strPtr(varStrForce(varNewBool(cfgOptionReset(optionId)))));
|
||||
// Add negate and reset
|
||||
kvPut(varKv(optionVar), varNewStr(strNew("negate")), varNewBool(cfgOptionNegate(optionId)));
|
||||
kvPut(varKv(optionVar), varNewStr(strNew("reset")), varNewBool(cfgOptionReset(optionId)));
|
||||
|
||||
// Add value if it is set
|
||||
if (cfgOptionTest(optionId))
|
||||
{
|
||||
strCat(result, ",\"value\":");
|
||||
const Variant *valueVar = NULL;
|
||||
|
||||
switch (cfgDefOptionType(cfgOptionDefIdFromId(optionId)))
|
||||
{
|
||||
@ -70,64 +72,47 @@ perlOptionJson(void)
|
||||
case cfgDefOptTypeFloat:
|
||||
case cfgDefOptTypeInteger:
|
||||
case cfgDefOptTypeSize:
|
||||
{
|
||||
strCat(result, strPtr(varStrForce(cfgOption(optionId))));
|
||||
break;
|
||||
}
|
||||
|
||||
case cfgDefOptTypeString:
|
||||
{
|
||||
strCatFmt(result, "\"%s\"", strPtr(cfgOptionStr(optionId)));
|
||||
valueVar = cfgOption(optionId);
|
||||
break;
|
||||
}
|
||||
|
||||
case cfgDefOptTypeHash:
|
||||
{
|
||||
valueVar = varNewKv();
|
||||
|
||||
const KeyValue *valueKv = cfgOptionKv(optionId);
|
||||
const VariantList *keyList = kvKeyList(valueKv);
|
||||
|
||||
strCat(result, "{");
|
||||
|
||||
for (unsigned int listIdx = 0; listIdx < varLstSize(keyList); listIdx++)
|
||||
{
|
||||
if (listIdx != 0)
|
||||
strCat(result, ",");
|
||||
|
||||
strCatFmt(
|
||||
result, "\"%s\":\"%s\"", strPtr(varStr(varLstGet(keyList, listIdx))),
|
||||
strPtr(varStr(kvGet(valueKv, varLstGet(keyList, listIdx)))));
|
||||
}
|
||||
|
||||
strCat(result, "}");
|
||||
kvPut(varKv(valueVar), varLstGet(keyList, listIdx), kvGet(valueKv, varLstGet(keyList, listIdx)));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case cfgDefOptTypeList:
|
||||
{
|
||||
StringList *valueList = strLstNewVarLst(cfgOptionLst(optionId));
|
||||
valueVar = varNewKv();
|
||||
|
||||
strCat(result, "{");
|
||||
const VariantList *valueList = cfgOptionLst(optionId);
|
||||
|
||||
for (unsigned int listIdx = 0; listIdx < strLstSize(valueList); listIdx++)
|
||||
{
|
||||
if (listIdx != 0)
|
||||
strCat(result, ",");
|
||||
|
||||
strCatFmt(result, "\"%s\":true", strPtr(strLstGet(valueList, listIdx)));
|
||||
}
|
||||
|
||||
strCat(result, "}");
|
||||
for (unsigned int listIdx = 0; listIdx < varLstSize(valueList); listIdx++)
|
||||
kvPut(varKv(valueVar), varLstGet(valueList, listIdx), varNewBool(true));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
kvPut(varKv(optionVar), varNewStr(strNew("value")), valueVar);
|
||||
}
|
||||
|
||||
strCat(result, "}");
|
||||
kvPut(configKv, varNewStr(strNew(cfgOptionName(optionId))), optionVar);
|
||||
}
|
||||
|
||||
strCat(result, "}");
|
||||
memContextSwitch(MEM_CONTEXT_OLD());
|
||||
result = kvToJson(configKv, 0);
|
||||
memContextSwitch(MEM_CONTEXT_TEMP());
|
||||
}
|
||||
MEM_CONTEXT_TEMP_END();
|
||||
|
||||
|
@ -8534,9 +8534,6 @@ static const EmbeddedModule embeddedModule[] =
|
||||
"\n"
|
||||
"eval\n"
|
||||
"{\n"
|
||||
"\n"
|
||||
"$$rstrConfigJson =~ s/\\\\/\\\\\\\\/g;\n"
|
||||
"\n"
|
||||
"%oOption = %{(JSON::PP->new()->allow_nonref())->decode($$rstrConfigJson)};\n"
|
||||
"return true;\n"
|
||||
"}\n"
|
||||
|
@ -34,6 +34,9 @@ testRun(void)
|
||||
cfgOptionValidSet(cfgOptPgHost, true);
|
||||
cfgOptionResetSet(cfgOptPgHost, true);
|
||||
|
||||
cfgOptionValidSet(cfgOptPgPath, true);
|
||||
cfgOptionSet(cfgOptPgPath, cfgSourceConfig, varNewStr(strNew("/path/db/pg")));
|
||||
|
||||
cfgOptionValidSet(cfgOptBackupStandby, true);
|
||||
cfgOptionResetSet(cfgOptBackupStandby, true);
|
||||
cfgOptionSet(cfgOptBackupStandby, cfgSourceParam, varNewBool(false));
|
||||
@ -44,6 +47,9 @@ testRun(void)
|
||||
cfgOptionValidSet(cfgOptArchivePushQueueMax, true);
|
||||
cfgOptionSet(cfgOptArchivePushQueueMax, cfgSourceParam, varNewInt64(999999999999));
|
||||
|
||||
cfgOptionValidSet(cfgOptRepoCipherPass, true);
|
||||
cfgOptionSet(cfgOptRepoCipherPass, cfgSourceConfig, varNewStr(strNew("part1\npart2")));
|
||||
|
||||
cfgOptionValidSet(cfgOptCompressLevel, true);
|
||||
cfgOptionSet(cfgOptCompressLevel, cfgSourceConfig, varNewInt(3));
|
||||
|
||||
@ -54,15 +60,18 @@ testRun(void)
|
||||
strPtr(perlOptionJson()),
|
||||
"{"
|
||||
"\"archive-push-queue-max\":"
|
||||
"{\"valid\":true,\"source\":\"param\",\"negate\":false,\"reset\":false,\"value\":999999999999},"
|
||||
"\"backup-standby\":{\"valid\":true,\"source\":\"param\",\"negate\":false,\"reset\":true,\"value\":false},"
|
||||
"\"compress\":{\"valid\":true,\"source\":\"param\",\"negate\":false,\"reset\":false,\"value\":true},"
|
||||
"\"compress-level\":{\"valid\":true,\"source\":\"config\",\"negate\":false,\"reset\":false,\"value\":3},"
|
||||
"\"config\":{\"valid\":true,\"source\":\"param\",\"negate\":true,\"reset\":false},"
|
||||
"\"online\":{\"valid\":true,\"source\":\"param\",\"negate\":true,\"reset\":false,\"value\":false},"
|
||||
"\"pg1-host\":{\"valid\":true,\"source\":\"default\",\"negate\":false,\"reset\":true},"
|
||||
"\"protocol-timeout\":{\"valid\":true,\"source\":\"param\",\"negate\":false,\"reset\":false,\"value\":1.1},"
|
||||
"\"stanza\":{\"valid\":true,\"source\":\"default\",\"negate\":false,\"reset\":false,\"value\":\"db\"}"
|
||||
"{\"negate\":false,\"reset\":false,\"source\":\"param\",\"valid\":true,\"value\":999999999999},"
|
||||
"\"backup-standby\":{\"negate\":false,\"reset\":true,\"source\":\"param\",\"valid\":true,\"value\":false},"
|
||||
"\"compress\":{\"negate\":false,\"reset\":false,\"source\":\"param\",\"valid\":true,\"value\":true},"
|
||||
"\"compress-level\":{\"negate\":false,\"reset\":false,\"source\":\"config\",\"valid\":true,\"value\":3},"
|
||||
"\"config\":{\"negate\":true,\"reset\":false,\"source\":\"param\",\"valid\":true},"
|
||||
"\"online\":{\"negate\":true,\"reset\":false,\"source\":\"param\",\"valid\":true,\"value\":false},"
|
||||
"\"pg1-host\":{\"negate\":false,\"reset\":true,\"source\":\"default\",\"valid\":true},"
|
||||
"\"pg1-path\":{\"negate\":false,\"reset\":false,\"source\":\"config\",\"valid\":true,\"value\":\"\\/path\\/db\\/pg\"},"
|
||||
"\"protocol-timeout\":{\"negate\":false,\"reset\":false,\"source\":\"param\",\"valid\":true,\"value\":1.1},"
|
||||
"\"repo1-cipher-pass\":{\"negate\":false,\"reset\":false,\"source\":\"config\",\"valid\":true,"
|
||||
"\"value\":\"part1\\npart2\"},"
|
||||
"\"stanza\":{\"negate\":false,\"reset\":false,\"source\":\"default\",\"valid\":true,\"value\":\"db\"}"
|
||||
"}",
|
||||
"simple options");
|
||||
|
||||
@ -97,12 +106,12 @@ testRun(void)
|
||||
TEST_RESULT_STR(
|
||||
strPtr(perlOptionJson()),
|
||||
"{"
|
||||
"\"db-include\":{\"valid\":true,\"source\":\"param\",\"negate\":false,\"reset\":false,"
|
||||
"\"db-include\":{\"negate\":false,\"reset\":false,\"source\":\"param\",\"valid\":true,"
|
||||
"\"value\":{\"db1\":true,\"db2\":true}},"
|
||||
"\"perl-option\":{\"valid\":true,\"source\":\"param\",\"negate\":false,\"reset\":false,"
|
||||
"\"perl-option\":{\"negate\":false,\"reset\":false,\"source\":\"param\",\"valid\":true,"
|
||||
"\"value\":{\"-I.\":true,\"-MDevel::Cover=-silent,1\":true}},"
|
||||
"\"recovery-option\":{\"valid\":true,\"source\":\"param\",\"negate\":false,\"reset\":false,"
|
||||
"\"value\":{\"standby_mode\":\"on\",\"primary_conn_info\":\"blah\"}}"
|
||||
"\"recovery-option\":{\"negate\":false,\"reset\":false,\"source\":\"param\",\"valid\":true,"
|
||||
"\"value\":{\"primary_conn_info\":\"blah\",\"standby_mode\":\"on\"}}"
|
||||
"}",
|
||||
"complex options");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user