Skip to content

Commit f6426a5

Browse files
committed
Updated http_client on Windows desktop to obey the client config
chunksize for handling the response body when explicitly set to by users. This allows users to configure for large data to avoid the overhead of processing small chunks of data at a time. The default still remains the same.
1 parent 4bb9dca commit f6426a5

File tree

2 files changed

+92
-61
lines changed

2 files changed

+92
-61
lines changed

Release/include/cpprest/http_client.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ class http_client_config
9292
http_client_config() :
9393
m_guarantee_order(false),
9494
m_timeout(utility::seconds(30)),
95-
m_chunksize(64 * 1024)
95+
m_chunksize(0)
9696
#if !defined(__cplusplus_winrt)
9797
, m_validate_certificates(true)
9898
#endif
@@ -178,7 +178,7 @@ class http_client_config
178178
/// <returns>The internal buffer size used by the http client when sending and receiving data from the network.</returns>
179179
size_t chunksize() const
180180
{
181-
return m_chunksize;
181+
return m_chunksize == 0 ? 64 * 1024 : m_chunksize;
182182
}
183183

184184
/// <summary>
@@ -191,6 +191,16 @@ class http_client_config
191191
m_chunksize = size;
192192
}
193193

194+
/// <summary>
195+
/// Returns true if the default chunk size is in use.
196+
/// <remarks>If true, implementations are allowed to choose whatever size is best.</remarks>
197+
/// </summary>
198+
/// <returns>True if default, false if set by user.</returns>
199+
bool is_default_chunksize() const
200+
{
201+
return m_chunksize == 0;
202+
}
203+
194204
#if !defined(__cplusplus_winrt)
195205
/// <summary>
196206
/// Gets the server certificate validation property.

Release/src/http/client/http_win7.cpp

Lines changed: 80 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,44 @@ class winhttp_client : public _http_client_communicator
696696
return has_proxy_credentials || has_server_credentials;
697697
}
698698

699+
// Helper function to query/read next part of response data from winhttp.
700+
static void read_next_response_chunk(winhttp_request_context *pContext, DWORD bytesRead, bool firstRead=false)
701+
{
702+
const bool defaultChunkSize = pContext->m_http_client->client_config().is_default_chunksize();
703+
704+
// If user specified a chunk size then read in chunks instead of using query data avaliable.
705+
if (defaultChunkSize)
706+
{
707+
if (!WinHttpQueryDataAvailable(pContext->m_request_handle, nullptr))
708+
{
709+
pContext->report_error(GetLastError(), _XPLATSTR("Error querying for http body data"));
710+
}
711+
}
712+
else
713+
{
714+
// If bytes read is less than the chunksize this request is done.
715+
const size_t chunkSize = pContext->m_http_client->client_config().chunksize();
716+
if (bytesRead < chunkSize && !firstRead)
717+
{
718+
pContext->complete_request((size_t) pContext->m_downloaded);
719+
}
720+
else
721+
{
722+
auto writebuf = pContext->_get_writebuffer();
723+
pContext->allocate_reply_space(writebuf.alloc(chunkSize), chunkSize);
724+
725+
if (!WinHttpReadData(
726+
pContext->m_request_handle,
727+
(LPVOID) pContext->m_body_data.get(),
728+
(DWORD) chunkSize,
729+
nullptr))
730+
{
731+
pContext->report_error(GetLastError(), _XPLATSTR("Error receiving http response body chunk"));
732+
}
733+
}
734+
}
735+
}
736+
699737
static void _transfer_encoding_chunked_write_data(_In_ winhttp_request_context * p_request_context)
700738
{
701739
const size_t chunk_size = p_request_context->m_http_client->client_config().chunksize();
@@ -1186,11 +1224,7 @@ class winhttp_client : public _http_client_communicator
11861224
// If none of them is specified, the message length should be determined by the server closing the connection.
11871225
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4
11881226

1189-
// WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE callback determines whether this function was successful and the value of the parameters.
1190-
if(!WinHttpQueryDataAvailable(hRequestHandle, nullptr))
1191-
{
1192-
p_request_context->report_error(GetLastError(), _XPLATSTR("Error querying for http body data"));
1193-
}
1227+
read_next_response_chunk(p_request_context, 0, true);
11941228
break;
11951229
}
11961230
case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE :
@@ -1201,9 +1235,6 @@ class winhttp_client : public _http_client_communicator
12011235
if(num_bytes > 0)
12021236
{
12031237
auto writebuf = p_request_context->_get_writebuffer();
1204-
if ( !_check_streambuf(p_request_context, writebuf, _XPLATSTR("Output stream is not open")) )
1205-
break;
1206-
12071238
p_request_context->allocate_reply_space(writebuf.alloc(num_bytes), num_bytes);
12081239

12091240
// Read in body all at once.
@@ -1237,68 +1268,58 @@ class winhttp_client : public _http_client_communicator
12371268
case WINHTTP_CALLBACK_STATUS_READ_COMPLETE :
12381269
{
12391270
// Status information length contains the number of bytes read.
1240-
// WinHTTP will always fill the whole buffer or read nothing.
1241-
// If number of bytes read is zero than we have reached the end.
1271+
const DWORD bytesRead = statusInfoLength;
12421272

1243-
if(statusInfoLength > 0)
1273+
// Report progress about downloaded bytes.
1274+
auto progress = p_request_context->m_request._get_impl()->_progress_handler();
1275+
p_request_context->m_downloaded += (size64_t) statusInfoLength;
1276+
if (progress)
12441277
{
1245-
auto progress = p_request_context->m_request._get_impl()->_progress_handler();
1246-
p_request_context->m_downloaded += (size64_t)statusInfoLength;
1247-
if ( progress )
1278+
try { (*progress)(message_direction::download, p_request_context->m_downloaded); }
1279+
catch (...)
12481280
{
1249-
try { (*progress)(message_direction::download, p_request_context->m_downloaded); } catch(...)
1281+
p_request_context->report_exception(std::current_exception());
1282+
return;
1283+
}
1284+
}
1285+
1286+
// If no bytes have been read, then this is the end of the response.
1287+
if (bytesRead == 0)
1288+
{
1289+
p_request_context->complete_request((size_t) p_request_context->m_downloaded);
1290+
break;
1291+
}
1292+
1293+
// If the data was allocated directly from the buffer then commit, otherwise we still
1294+
// need to write to the response stream buffer.
1295+
auto writebuf = p_request_context->_get_writebuffer();
1296+
if (p_request_context->is_externally_allocated())
1297+
{
1298+
writebuf.commit(bytesRead);
1299+
read_next_response_chunk(p_request_context, bytesRead);
1300+
}
1301+
else
1302+
{
1303+
writebuf.putn(p_request_context->m_body_data.get(), bytesRead).then(
1304+
[hRequestHandle, p_request_context, bytesRead] (pplx::task<size_t> op)
1305+
{
1306+
size_t written = 0;
1307+
try { written = op.get(); }
1308+
catch (...)
12501309
{
12511310
p_request_context->report_exception(std::current_exception());
12521311
return;
12531312
}
1254-
}
12551313

1256-
auto writebuf = p_request_context->_get_writebuffer();
1257-
1258-
if ( p_request_context->is_externally_allocated() )
1259-
{
1260-
writebuf.commit(statusInfoLength);
1261-
1262-
// Look for more data
1263-
if (!WinHttpQueryDataAvailable(hRequestHandle, nullptr))
1314+
// If we couldn't write everything, it's time to exit.
1315+
if (written != bytesRead)
12641316
{
1265-
p_request_context->report_error(GetLastError(), _XPLATSTR("Error querying for http body chunk"));
1317+
p_request_context->report_exception(std::runtime_error("response stream unexpectedly failed to write the requested number of bytes"));
12661318
return;
12671319
}
1268-
}
1269-
else
1270-
{
1271-
writebuf.putn(p_request_context->m_body_data.get(), statusInfoLength).then(
1272-
[hRequestHandle, p_request_context, statusInfoLength]
1273-
(pplx::task<size_t> op)
1274-
{
1275-
size_t written = 0;
1276-
try { written = op.get(); } catch(...)
1277-
{
1278-
p_request_context->report_exception(std::current_exception());
1279-
return;
1280-
}
1281-
1282-
// If we couldn't write everything, it's time to exit.
1283-
if ( written != statusInfoLength )
1284-
{
1285-
p_request_context->report_exception(std::runtime_error("response stream unexpectedly failed to write the requested number of bytes"));
1286-
return;
1287-
}
1288-
1289-
// Look for more data
1290-
if (!WinHttpQueryDataAvailable(hRequestHandle, nullptr))
1291-
{
1292-
p_request_context->report_error(GetLastError(), _XPLATSTR("Error querying for http body chunk"));
1293-
return;
1294-
}
1295-
});
1296-
}
1297-
}
1298-
else
1299-
{
1300-
// Done reading so set task completion event and close the request handle.
1301-
p_request_context->complete_request((size_t)p_request_context->m_downloaded);
1320+
1321+
read_next_response_chunk(p_request_context, bytesRead);
1322+
});
13021323
}
13031324
break;
13041325
}

0 commit comments

Comments
 (0)