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

Add EOF detection to content read in HttpClient.

If the connection closed before all content was sent httpClientRead() would get stuck in an infinite loop waiting for it to arrive.

EOF should never be reached during content read so immediately error if EOF is detected.
This commit is contained in:
David Steele 2018-11-24 09:12:44 -05:00
parent f4a1751abc
commit 7a1a688835
2 changed files with 62 additions and 1 deletions

View File

@ -96,7 +96,7 @@ httpClientRead(HttpClient *this, Buffer *buffer, bool block)
// Read if there is content remaining
if (this->contentRemaining > 0)
{
// If the buffer is larger than the content that needs to read then limit the buffer size so the read won't block
// If the buffer is larger than the content that needs to be read then limit the buffer size so the read won't block
// or read too far. Casting to size_t is safe on 32-bit because we know the max buffer size is defined as less than
// 2^32 so content remaining can't be more than that.
if (bufRemains(buffer) > this->contentRemaining)
@ -104,6 +104,10 @@ httpClientRead(HttpClient *this, Buffer *buffer, bool block)
this->contentRemaining -= ioRead(tlsClientIoRead(this->tls), buffer);
// Error if EOF but content read is not complete
if (ioReadEof(tlsClientIoRead(this->tls)))
THROW(FileReadError, "unexpected EOF reading HTTP content");
// Clear limit (this works even if the limit was not set and it is easier than checking)
bufLimitClear(buffer);
}

View File

@ -207,6 +207,48 @@ testHttpServer(void)
harnessTlsServerClose();
// Request with eof before content complete with retry
harnessTlsServerAccept();
harnessTlsServerExpect(
"GET /path/file%201.txt HTTP/1.1\r\n"
"\r\n");
harnessTlsServerReply(
"HTTP/1.1 200 OK\r\n"
"content-length:32\r\n"
"\r\n"
"0123456789012345678901234567890");
harnessTlsServerClose();
harnessTlsServerAccept();
harnessTlsServerExpect(
"GET /path/file%201.txt HTTP/1.1\r\n"
"\r\n");
harnessTlsServerReply(
"HTTP/1.1 200 OK\r\n"
"content-length:32\r\n"
"\r\n"
"01234567890123456789012345678901");
// Request with eof before content complete
harnessTlsServerAccept();
harnessTlsServerExpect(
"GET /path/file%201.txt HTTP/1.1\r\n"
"\r\n");
harnessTlsServerReply(
"HTTP/1.1 200 OK\r\n"
"content-length:32\r\n"
"\r\n"
"0123456789012345678901234567890");
harnessTlsServerClose();
// Request with chunked content
harnessTlsServerAccept();
@ -425,6 +467,21 @@ testRun(void)
TEST_RESULT_STR(strPtr(strNewBuf(buffer)), "01234567890123456789012345678901", " check response");
TEST_RESULT_UINT(httpClientRead(client, bufNew(1), true), 0, " call internal read to check eof");
// Request with eof before content complete with retry
TEST_ASSIGN(
buffer, httpClientRequest(client, strNew("GET"), strNew("/path/file 1.txt"), NULL, NULL, true),
"request with content length retry");
TEST_RESULT_STR(strPtr(strNewBuf(buffer)), "01234567890123456789012345678901", " check response");
TEST_RESULT_UINT(httpClientRead(client, bufNew(1), true), 0, " call internal read to check eof");
// Request with eof before content and error
buffer = bufNew(32);
TEST_RESULT_VOID(
httpClientRequest(client, strNew("GET"), strNew("/path/file 1.txt"), NULL, NULL, false),
"request with content length error");
TEST_ERROR(
ioRead(httpClientIoRead(client), buffer), FileReadError, "unexpected EOF reading HTTP content");
// Request with content using chunked encoding
TEST_RESULT_VOID(httpClientRequest(client, strNew("GET"), strNew("/"), NULL, NULL, false), "request with chunked encoding");
TEST_RESULT_STR(