mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-03-03 14:52:21 +02:00
Fix C code to recognize host:port format like Perl does.
This was not an intentional feature in Perl, but it works, so it makes sense to implement the same syntax in C. This is a break from other places where a -port option is explicitly supplied, so it may make sense to support both styles going forward. This commit does not address that, however. Reported by Kyle Nevins.
This commit is contained in:
parent
3aa521fed0
commit
df12cbb162
@ -33,6 +33,14 @@
|
||||
<p>Fix issue setting <br-option>log-level-file=off</br-option> for the <cmd>archive-get</cmd> command.</p>
|
||||
</release-item>
|
||||
|
||||
<release-item>
|
||||
<release-item-contributor-list>
|
||||
<release-item-ideator id="kyle.nevins"/>
|
||||
</release-item-contributor-list>
|
||||
|
||||
<p>Fix C code to recognize <id>host:port</id> option format like Perl does.</p>
|
||||
</release-item>
|
||||
|
||||
<release-item>
|
||||
<p>Fix issues with <code>remote</code>/<code>local</code> command logging options.</p>
|
||||
</release-item>
|
||||
@ -6804,6 +6812,11 @@
|
||||
<contributor-id type="github">keithf4</contributor-id>
|
||||
</contributor>
|
||||
|
||||
<contributor id="kyle.nevins">
|
||||
<contributor-name-display>Kyle Nevins</contributor-name-display>
|
||||
<contributor-id type="github">kyle-nevins</contributor-id>
|
||||
</contributor>
|
||||
|
||||
<contributor id="laetitia">
|
||||
<contributor-name-display>L&aelig;titia</contributor-name-display>
|
||||
<contributor-id type="github">LaetitiaLoxo</contributor-id>
|
||||
|
@ -545,6 +545,78 @@ cfgOptionDefaultSet(ConfigOption optionId, const Variant *defaultValue)
|
||||
FUNCTION_TEST_RETURN_VOID();
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Parse a host option and extract the host and port (if it exists)
|
||||
***********************************************************************************************************************************/
|
||||
String *
|
||||
cfgOptionHostPort(ConfigOption optionId, unsigned int *port)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_PARAM_P(UINT, port);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(optionId < CFG_OPTION_TOTAL);
|
||||
ASSERT(port != NULL);
|
||||
|
||||
String *result = NULL;
|
||||
|
||||
// Proceed if option is valid and has a value
|
||||
if (cfgOptionTest(optionId))
|
||||
{
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
const String *host = cfgOptionStr(optionId);
|
||||
|
||||
// If the host contains a colon then it has a port appended
|
||||
if (strChr(host, ':') != -1)
|
||||
{
|
||||
const StringList *hostPart = strLstNewSplitZ(host, ":");
|
||||
|
||||
// More than one colon is invalid
|
||||
if (strLstSize(hostPart) > 2)
|
||||
{
|
||||
THROW_FMT(
|
||||
OptionInvalidError,
|
||||
"'%s' is not valid for option '%s'"
|
||||
"\nHINT: is more than one port specified?",
|
||||
strPtr(host), cfgOptionName(optionId));
|
||||
}
|
||||
|
||||
// Set the host
|
||||
memContextSwitch(MEM_CONTEXT_OLD());
|
||||
result = strDup(strLstGet(hostPart, 0));
|
||||
memContextSwitch(MEM_CONTEXT_TEMP());
|
||||
|
||||
// Set the port and error if it is not a positive integer
|
||||
TRY_BEGIN()
|
||||
{
|
||||
*port = cvtZToUInt(strPtr(strLstGet(hostPart, 1)));
|
||||
}
|
||||
CATCH(FormatError)
|
||||
{
|
||||
THROW_FMT(
|
||||
OptionInvalidError,
|
||||
"'%s' is not valid for option '%s'"
|
||||
"\nHINT: port is not a positive integer.",
|
||||
strPtr(host), cfgOptionName(optionId));
|
||||
}
|
||||
TRY_END();
|
||||
}
|
||||
// Else there is no port and just copy the host
|
||||
else
|
||||
{
|
||||
memContextSwitch(MEM_CONTEXT_OLD());
|
||||
result = strDup(host);
|
||||
memContextSwitch(MEM_CONTEXT_TEMP());
|
||||
}
|
||||
}
|
||||
MEM_CONTEXT_TEMP_END();
|
||||
}
|
||||
|
||||
FUNCTION_TEST_RETURN(result);
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Get index for option
|
||||
***********************************************************************************************************************************/
|
||||
|
@ -100,6 +100,7 @@ void cfgExeSet(const String *exeParam);
|
||||
const Variant *cfgOptionDefault(ConfigOption optionId);
|
||||
void cfgOptionDefaultSet(ConfigOption optionId, const Variant *defaultValue);
|
||||
ConfigDefineOption cfgOptionDefIdFromId(ConfigOption optionId);
|
||||
String *cfgOptionHostPort(ConfigOption optionId, unsigned int *port);
|
||||
int cfgOptionId(const char *optionName);
|
||||
ConfigOption cfgOptionIdFromDefId(ConfigDefineOption optionDefId, unsigned int index);
|
||||
bool cfgOptionNegate(ConfigOption optionId);
|
||||
|
@ -78,6 +78,7 @@ struct StorageDriverS3
|
||||
const String *securityToken; // Security token, if any
|
||||
size_t partSize; // Part size for multi-part upload
|
||||
const String *host; // Defaults to {bucket}.{endpoint}
|
||||
unsigned int port; // Host port
|
||||
|
||||
// Current signing key and date it is valid for
|
||||
const String *signingKeyDate; // Date of cached signing key (so we know when to regenerate)
|
||||
@ -261,6 +262,7 @@ storageDriverS3New(
|
||||
this->securityToken = strDup(securityToken);
|
||||
this->partSize = partSize;
|
||||
this->host = host == NULL ? strNewFmt("%s.%s", strPtr(bucket), strPtr(endPoint)) : strDup(host);
|
||||
this->port = port;
|
||||
|
||||
// Force the signing key to be generated on the first run
|
||||
this->signingKeyDate = YYYYMMDD_STR;
|
||||
@ -276,7 +278,7 @@ storageDriverS3New(
|
||||
.pathSync = (StorageInterfacePathSync)storageDriverS3PathSync, .remove = (StorageInterfaceRemove)storageDriverS3Remove);
|
||||
|
||||
// Create the http client used to service requests
|
||||
this->httpClient = httpClientNew(this->host, port, timeout, verifyPeer, caFile, caPath);
|
||||
this->httpClient = httpClientNew(this->host, this->port, timeout, verifyPeer, caFile, caPath);
|
||||
this->headerRedactList = strLstAdd(strLstNew(), S3_HEADER_AUTHORIZATION_STR);
|
||||
}
|
||||
MEM_CONTEXT_NEW_END();
|
||||
|
@ -302,13 +302,19 @@ storageRepoGet(const String *type, bool write)
|
||||
// Use the S3 driver
|
||||
else if (strEqZ(type, STORAGE_TYPE_S3))
|
||||
{
|
||||
// Set the default port
|
||||
unsigned int port = STORAGE_DRIVER_S3_PORT_DEFAULT;
|
||||
|
||||
// Extract port from the endpoint and host if it is present
|
||||
const String *endPoint = cfgOptionHostPort(cfgOptRepoS3Endpoint, &port);
|
||||
const String *host = cfgOptionHostPort(cfgOptRepoS3Host, &port);
|
||||
|
||||
result = storageDriverS3Interface(
|
||||
storageDriverS3New(
|
||||
cfgOptionStr(cfgOptRepoPath), write, storageRepoPathExpression, cfgOptionStr(cfgOptRepoS3Bucket),
|
||||
cfgOptionStr(cfgOptRepoS3Endpoint), cfgOptionStr(cfgOptRepoS3Region), cfgOptionStr(cfgOptRepoS3Key),
|
||||
cfgOptionStr(cfgOptRepoS3KeySecret), cfgOptionTest(cfgOptRepoS3Token) ? cfgOptionStr(cfgOptRepoS3Token) : NULL,
|
||||
(size_t)5 * 1024 * 1024, cfgOptionTest(cfgOptRepoS3Host) ? cfgOptionStr(cfgOptRepoS3Host) : NULL,
|
||||
STORAGE_DRIVER_S3_PORT_DEFAULT, STORAGE_DRIVER_S3_TIMEOUT_DEFAULT, cfgOptionBool(cfgOptRepoS3VerifySsl),
|
||||
endPoint, cfgOptionStr(cfgOptRepoS3Region), cfgOptionStr(cfgOptRepoS3Key), cfgOptionStr(cfgOptRepoS3KeySecret),
|
||||
cfgOptionTest(cfgOptRepoS3Token) ? cfgOptionStr(cfgOptRepoS3Token) : NULL, (size_t)5 * 1024 * 1024, host, port,
|
||||
STORAGE_DRIVER_S3_TIMEOUT_DEFAULT, cfgOptionBool(cfgOptRepoS3VerifySsl),
|
||||
cfgOptionTest(cfgOptRepoS3CaFile) ? cfgOptionStr(cfgOptRepoS3CaFile) : NULL,
|
||||
cfgOptionTest(cfgOptRepoS3CaPath) ? cfgOptionStr(cfgOptRepoS3CaPath) : NULL));
|
||||
}
|
||||
|
@ -375,7 +375,7 @@ unit:
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------------------------------
|
||||
- name: config
|
||||
total: 3
|
||||
total: 4
|
||||
|
||||
coverage:
|
||||
config/config: full
|
||||
|
@ -194,6 +194,42 @@ testRun(void)
|
||||
TEST_RESULT_INT(cfgCommand(), cfgCmdNone, "command begins as none");
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************************
|
||||
if (testBegin("cfgOptionHostPort()"))
|
||||
{
|
||||
unsigned int port = 55555;
|
||||
|
||||
cfgInit();
|
||||
cfgCommandSet(cfgCmdBackup);
|
||||
|
||||
cfgOptionValidSet(cfgOptRepoS3Host, true);
|
||||
cfgOptionSet(cfgOptRepoS3Host, cfgSourceConfig, varNewStrZ("host.com")) ;
|
||||
TEST_RESULT_STR(strPtr(cfgOptionHostPort(cfgOptRepoS3Host, &port)), "host.com", "check plain host");
|
||||
TEST_RESULT_UINT(port, 55555, "check that port was not updated");
|
||||
|
||||
cfgOptionSet(cfgOptRepoS3Host, cfgSourceConfig, varNewStrZ("myhost.com:777")) ;
|
||||
TEST_RESULT_STR(strPtr(cfgOptionHostPort(cfgOptRepoS3Host, &port)), "myhost.com", "check host with port");
|
||||
TEST_RESULT_UINT(port, 777, "check that port was updated");
|
||||
|
||||
TEST_RESULT_STR(strPtr(cfgOptionHostPort(cfgOptRepoS3Endpoint, &port)), NULL, "check null host");
|
||||
TEST_RESULT_UINT(port, 777, "check that port was not updated");
|
||||
|
||||
cfgOptionSet(cfgOptRepoS3Host, cfgSourceConfig, varNewStrZ("myhost.com:777:888")) ;
|
||||
TEST_ERROR(
|
||||
cfgOptionHostPort(cfgOptRepoS3Host, &port), OptionInvalidError,
|
||||
"'myhost.com:777:888' is not valid for option 'repo1-s3-host'"
|
||||
"\nHINT: is more than one port specified?");
|
||||
TEST_RESULT_UINT(port, 777, "check that port was not updated");
|
||||
|
||||
cfgOptionValidSet(cfgOptRepoS3Endpoint, true);
|
||||
cfgOptionSet(cfgOptRepoS3Endpoint, cfgSourceConfig, varNewStrZ("myendpoint.com:ZZZ")) ;
|
||||
TEST_ERROR(
|
||||
cfgOptionHostPort(cfgOptRepoS3Endpoint, &port), OptionInvalidError,
|
||||
"'myendpoint.com:ZZZ' is not valid for option 'repo1-s3-endpoint'"
|
||||
"\nHINT: port is not a positive integer.");
|
||||
TEST_RESULT_UINT(port, 777, "check that port was not updated");
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************************
|
||||
if (testBegin("cfgOptionDefault() and cfgOptionDefaultSet()"))
|
||||
{
|
||||
|
@ -384,6 +384,66 @@ testRun(void)
|
||||
TEST_RESULT_STR(strPtr(((StorageDriverS3 *)storage->driver)->bucket), strPtr(bucket), " check bucket");
|
||||
TEST_RESULT_STR(strPtr(((StorageDriverS3 *)storage->driver)->region), strPtr(region), " check region");
|
||||
TEST_RESULT_STR(strPtr(((StorageDriverS3 *)storage->driver)->host), strPtr(host), " check host");
|
||||
TEST_RESULT_UINT(((StorageDriverS3 *)storage->driver)->port, 443, " check port");
|
||||
TEST_RESULT_STR(strPtr(((StorageDriverS3 *)storage->driver)->accessKey), strPtr(accessKey), " check access key");
|
||||
TEST_RESULT_STR(
|
||||
strPtr(((StorageDriverS3 *)storage->driver)->secretAccessKey), strPtr(secretAccessKey), " check secret access key");
|
||||
TEST_RESULT_STR(
|
||||
strPtr(((StorageDriverS3 *)storage->driver)->securityToken), strPtr(securityToken), " check security token");
|
||||
|
||||
// Add a port to the endpoint
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
argList = strLstNew();
|
||||
strLstAddZ(argList, "pgbackrest");
|
||||
strLstAddZ(argList, "--stanza=db");
|
||||
strLstAddZ(argList, "--repo1-type=s3");
|
||||
strLstAdd(argList, strNewFmt("--repo1-path=%s", strPtr(path)));
|
||||
strLstAdd(argList, strNewFmt("--repo1-s3-bucket=%s", strPtr(bucket)));
|
||||
strLstAdd(argList, strNewFmt("--repo1-s3-region=%s", strPtr(region)));
|
||||
strLstAdd(argList, strNewFmt("--repo1-s3-endpoint=%s:999", strPtr(endPoint)));
|
||||
strLstAddZ(argList, "--repo1-s3-ca-path=" TLS_CERT_FAKE_PATH);
|
||||
strLstAddZ(argList, "--repo1-s3-ca-file=" TLS_CERT_FAKE_PATH "/pgbackrest-test.crt");
|
||||
setenv("PGBACKREST_REPO1_S3_KEY", strPtr(accessKey), true);
|
||||
setenv("PGBACKREST_REPO1_S3_KEY_SECRET", strPtr(secretAccessKey), true);
|
||||
setenv("PGBACKREST_REPO1_S3_TOKEN", strPtr(securityToken), true);
|
||||
strLstAddZ(argList, "archive-get");
|
||||
harnessCfgLoad(strLstSize(argList), strLstPtr(argList));
|
||||
|
||||
TEST_ASSIGN(storage, storageRepoGet(strNew(STORAGE_TYPE_S3), false), "get S3 repo storage with options");
|
||||
TEST_RESULT_STR(strPtr(((StorageDriverS3 *)storage->driver)->bucket), strPtr(bucket), " check bucket");
|
||||
TEST_RESULT_STR(strPtr(((StorageDriverS3 *)storage->driver)->region), strPtr(region), " check region");
|
||||
TEST_RESULT_STR(strPtr(((StorageDriverS3 *)storage->driver)->host), strPtr(strNewFmt("%s.%s", strPtr(bucket), strPtr(endPoint))), " check host");
|
||||
TEST_RESULT_UINT(((StorageDriverS3 *)storage->driver)->port, 999, " check port");
|
||||
TEST_RESULT_STR(strPtr(((StorageDriverS3 *)storage->driver)->accessKey), strPtr(accessKey), " check access key");
|
||||
TEST_RESULT_STR(
|
||||
strPtr(((StorageDriverS3 *)storage->driver)->secretAccessKey), strPtr(secretAccessKey), " check secret access key");
|
||||
TEST_RESULT_STR(
|
||||
strPtr(((StorageDriverS3 *)storage->driver)->securityToken), strPtr(securityToken), " check security token");
|
||||
|
||||
// Also add port to the host
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
argList = strLstNew();
|
||||
strLstAddZ(argList, "pgbackrest");
|
||||
strLstAddZ(argList, "--stanza=db");
|
||||
strLstAddZ(argList, "--repo1-type=s3");
|
||||
strLstAdd(argList, strNewFmt("--repo1-path=%s", strPtr(path)));
|
||||
strLstAdd(argList, strNewFmt("--repo1-s3-bucket=%s", strPtr(bucket)));
|
||||
strLstAdd(argList, strNewFmt("--repo1-s3-region=%s", strPtr(region)));
|
||||
strLstAdd(argList, strNewFmt("--repo1-s3-endpoint=%s:999", strPtr(endPoint)));
|
||||
strLstAdd(argList, strNewFmt("--repo1-s3-host=%s:7777", strPtr(host)));
|
||||
strLstAddZ(argList, "--repo1-s3-ca-path=" TLS_CERT_FAKE_PATH);
|
||||
strLstAddZ(argList, "--repo1-s3-ca-file=" TLS_CERT_FAKE_PATH "/pgbackrest-test.crt");
|
||||
setenv("PGBACKREST_REPO1_S3_KEY", strPtr(accessKey), true);
|
||||
setenv("PGBACKREST_REPO1_S3_KEY_SECRET", strPtr(secretAccessKey), true);
|
||||
setenv("PGBACKREST_REPO1_S3_TOKEN", strPtr(securityToken), true);
|
||||
strLstAddZ(argList, "archive-get");
|
||||
harnessCfgLoad(strLstSize(argList), strLstPtr(argList));
|
||||
|
||||
TEST_ASSIGN(storage, storageRepoGet(strNew(STORAGE_TYPE_S3), false), "get S3 repo storage with options");
|
||||
TEST_RESULT_STR(strPtr(((StorageDriverS3 *)storage->driver)->bucket), strPtr(bucket), " check bucket");
|
||||
TEST_RESULT_STR(strPtr(((StorageDriverS3 *)storage->driver)->region), strPtr(region), " check region");
|
||||
TEST_RESULT_STR(strPtr(((StorageDriverS3 *)storage->driver)->host), strPtr(host), " check host");
|
||||
TEST_RESULT_UINT(((StorageDriverS3 *)storage->driver)->port, 7777, " check port");
|
||||
TEST_RESULT_STR(strPtr(((StorageDriverS3 *)storage->driver)->accessKey), strPtr(accessKey), " check access key");
|
||||
TEST_RESULT_STR(
|
||||
strPtr(((StorageDriverS3 *)storage->driver)->secretAccessKey), strPtr(secretAccessKey), " check secret access key");
|
||||
|
Loading…
x
Reference in New Issue
Block a user