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:
parent
f4a1751abc
commit
7a1a688835
@ -96,7 +96,7 @@ httpClientRead(HttpClient *this, Buffer *buffer, bool block)
|
|||||||
// Read if there is content remaining
|
// Read if there is content remaining
|
||||||
if (this->contentRemaining > 0)
|
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
|
// 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.
|
// 2^32 so content remaining can't be more than that.
|
||||||
if (bufRemains(buffer) > this->contentRemaining)
|
if (bufRemains(buffer) > this->contentRemaining)
|
||||||
@ -104,6 +104,10 @@ httpClientRead(HttpClient *this, Buffer *buffer, bool block)
|
|||||||
|
|
||||||
this->contentRemaining -= ioRead(tlsClientIoRead(this->tls), buffer);
|
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)
|
// Clear limit (this works even if the limit was not set and it is easier than checking)
|
||||||
bufLimitClear(buffer);
|
bufLimitClear(buffer);
|
||||||
}
|
}
|
||||||
|
@ -207,6 +207,48 @@ testHttpServer(void)
|
|||||||
|
|
||||||
harnessTlsServerClose();
|
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
|
// Request with chunked content
|
||||||
harnessTlsServerAccept();
|
harnessTlsServerAccept();
|
||||||
|
|
||||||
@ -425,6 +467,21 @@ testRun(void)
|
|||||||
TEST_RESULT_STR(strPtr(strNewBuf(buffer)), "01234567890123456789012345678901", " check response");
|
TEST_RESULT_STR(strPtr(strNewBuf(buffer)), "01234567890123456789012345678901", " check response");
|
||||||
TEST_RESULT_UINT(httpClientRead(client, bufNew(1), true), 0, " call internal read to check eof");
|
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
|
// Request with content using chunked encoding
|
||||||
TEST_RESULT_VOID(httpClientRequest(client, strNew("GET"), strNew("/"), NULL, NULL, false), "request with chunked encoding");
|
TEST_RESULT_VOID(httpClientRequest(client, strNew("GET"), strNew("/"), NULL, NULL, false), "request with chunked encoding");
|
||||||
TEST_RESULT_STR(
|
TEST_RESULT_STR(
|
||||||
|
Loading…
Reference in New Issue
Block a user