1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2024-12-14 10:13:05 +02:00

Fix handling of repeated HTTP headers.

When HTTP headers are repeated they should be considered equivalent to a single comma-separated header rather than generating an error, which was the prior behavior.

Reported by donicrosby.
This commit is contained in:
David Steele 2019-11-08 18:58:45 -05:00
parent 4317178633
commit 10c8eeaf6c
3 changed files with 37 additions and 8 deletions

View File

@ -25,6 +25,16 @@
<p>When performing a delta restore on a largely unchanged cluster the remote could timeout if no files were fetched from the repository within <br-option>protocol-timeout</br-option>. Add keep-alives to prevent remote timeout.</p>
</release-item>
<release-item>
<release-item-contributor-list>
<release-item-ideator id="donicrosby"/>
</release-item-contributor-list>
<p>Fix handling of repeated HTTP headers.</p>
<p>When HTTP headers are repeated they should be considered equivalent to a single comma-separated header rather than generating an error, which was the prior behavior.</p>
</release-item>
</release-bug-list>
<release-improvement-list>
@ -7558,6 +7568,11 @@
<contributor-id type="github">anarazel</contributor-id>
</contributor>
<contributor id="donicrosby">
<contributor-name-display>donicrosby</contributor-name-display>
<contributor-id type="github">donicrosby</contributor-id>
</contributor>
<contributor id="douglas.j.hunley">
<contributor-name-display>Douglas J Hunley</contributor-name-display>
<contributor-id type="github">hunleyd</contributor-id>

View File

@ -93,14 +93,28 @@ httpHeaderAdd(HttpHeader *this, const String *key, const String *value)
ASSERT(key != NULL);
ASSERT(value != NULL);
// Make sure the key does not already exist
// Check if the key already exists
const Variant *keyVar = VARSTR(key);
const Variant *valueVar = kvGet(this->kv, keyVar);
if (kvGet(this->kv, keyVar) != NULL)
THROW_FMT(AssertError, "key '%s' already exists", strPtr(key));
// If the key exists then append the new value. The HTTP spec (RFC 2616, Section 4.2) says that if a header appears more than
// once then it is equivalent to a single comma-separated header. There appear to be a few exceptions such as Set-Cookie, but
// they should not be of concern to us here.
if (valueVar != NULL)
{
MEM_CONTEXT_TEMP_BEGIN()
{
String *valueAppend = strDup(varStr(valueVar));
strCat(valueAppend, ", ");
strCat(valueAppend, strPtr(value));
// Store the key
kvPut(this->kv, keyVar, VARSTR(value));
kvPut(this->kv, keyVar, VARSTR(valueAppend));
}
MEM_CONTEXT_TEMP_END();
}
// Else store the key
else
kvPut(this->kv, keyVar, VARSTR(value));
FUNCTION_TEST_RETURN(this);
}

View File

@ -326,17 +326,17 @@ testRun(void)
MEM_CONTEXT_TEMP_END();
TEST_RESULT_PTR(httpHeaderAdd(header, strNew("key2"), strNew("value2")), header, "add header");
TEST_ERROR(httpHeaderAdd(header, strNew("key2"), strNew("value2")), AssertError, "key 'key2' already exists");
TEST_RESULT_PTR(httpHeaderPut(header, strNew("key2"), strNew("value2a")), header, "put header");
TEST_RESULT_PTR(httpHeaderAdd(header, strNew("key2"), strNew("value2b")), header, "add header");
TEST_RESULT_PTR(httpHeaderAdd(header, strNew("key1"), strNew("value1")), header, "add header");
TEST_RESULT_STR(strPtr(strLstJoin(httpHeaderList(header), ", ")), "key1, key2", "header list");
TEST_RESULT_STR(strPtr(httpHeaderGet(header, strNew("key1"))), "value1", "get value");
TEST_RESULT_STR(strPtr(httpHeaderGet(header, strNew("key2"))), "value2a", "get value");
TEST_RESULT_STR(strPtr(httpHeaderGet(header, strNew("key2"))), "value2a, value2b", "get value");
TEST_RESULT_PTR(httpHeaderGet(header, strNew(BOGUS_STR)), NULL, "get missing value");
TEST_RESULT_STR(strPtr(httpHeaderToLog(header)), "{key1: 'value1', key2: 'value2a'}", "log output");
TEST_RESULT_STR(strPtr(httpHeaderToLog(header)), "{key1: 'value1', key2: 'value2a, value2b'}", "log output");
TEST_RESULT_VOID(httpHeaderFree(header), "free header");