@@ -696,6 +696,44 @@ class winhttp_client : public _http_client_communicator
696
696
return has_proxy_credentials || has_server_credentials;
697
697
}
698
698
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
+
699
737
static void _transfer_encoding_chunked_write_data (_In_ winhttp_request_context * p_request_context)
700
738
{
701
739
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
1186
1224
// If none of them is specified, the message length should be determined by the server closing the connection.
1187
1225
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4
1188
1226
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 );
1194
1228
break ;
1195
1229
}
1196
1230
case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE :
@@ -1201,9 +1235,6 @@ class winhttp_client : public _http_client_communicator
1201
1235
if (num_bytes > 0 )
1202
1236
{
1203
1237
auto writebuf = p_request_context->_get_writebuffer ();
1204
- if ( !_check_streambuf (p_request_context, writebuf, _XPLATSTR (" Output stream is not open" )) )
1205
- break ;
1206
-
1207
1238
p_request_context->allocate_reply_space (writebuf.alloc (num_bytes), num_bytes);
1208
1239
1209
1240
// Read in body all at once.
@@ -1237,68 +1268,58 @@ class winhttp_client : public _http_client_communicator
1237
1268
case WINHTTP_CALLBACK_STATUS_READ_COMPLETE :
1238
1269
{
1239
1270
// 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;
1242
1272
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)
1244
1277
{
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 (...)
1248
1280
{
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 (...)
1250
1309
{
1251
1310
p_request_context->report_exception (std::current_exception ());
1252
1311
return ;
1253
1312
}
1254
- }
1255
1313
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)
1264
1316
{
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 " ));
1266
1318
return ;
1267
1319
}
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
+ });
1302
1323
}
1303
1324
break ;
1304
1325
}
0 commit comments