@@ -589,7 +589,7 @@ class winhttp_client : public _http_client_communicator
589
589
if (!WinHttpAddRequestHeaders (
590
590
winhttp_context->m_request_handle ,
591
591
flattened_headers.c_str (),
592
- ( DWORD) flattened_headers.length (),
592
+ static_cast < DWORD>( flattened_headers.length () ),
593
593
WINHTTP_ADDREQ_FLAG_ADD))
594
594
{
595
595
request->report_error (GetLastError (), _XPLATSTR (" Error adding request headers" ));
@@ -704,6 +704,44 @@ class winhttp_client : public _http_client_communicator
704
704
return has_proxy_credentials || has_server_credentials;
705
705
}
706
706
707
+ // Helper function to query/read next part of response data from winhttp.
708
+ static void read_next_response_chunk (winhttp_request_context *pContext, DWORD bytesRead, bool firstRead=false )
709
+ {
710
+ const bool defaultChunkSize = pContext->m_http_client ->client_config ().is_default_chunksize ();
711
+
712
+ // If user specified a chunk size then read in chunks instead of using query data avaliable.
713
+ if (defaultChunkSize)
714
+ {
715
+ if (!WinHttpQueryDataAvailable (pContext->m_request_handle , nullptr ))
716
+ {
717
+ pContext->report_error (GetLastError (), _XPLATSTR (" Error querying for http body data" ));
718
+ }
719
+ }
720
+ else
721
+ {
722
+ // If bytes read is less than the chunksize this request is done.
723
+ const size_t chunkSize = pContext->m_http_client ->client_config ().chunksize ();
724
+ if (bytesRead < chunkSize && !firstRead)
725
+ {
726
+ pContext->complete_request (pContext->m_downloaded );
727
+ }
728
+ else
729
+ {
730
+ auto writebuf = pContext->_get_writebuffer ();
731
+ pContext->allocate_reply_space (writebuf.alloc (chunkSize), chunkSize);
732
+
733
+ if (!WinHttpReadData (
734
+ pContext->m_request_handle ,
735
+ pContext->m_body_data .get (),
736
+ static_cast <DWORD>(chunkSize),
737
+ nullptr ))
738
+ {
739
+ pContext->report_error (GetLastError (), _XPLATSTR (" Error receiving http response body chunk" ));
740
+ }
741
+ }
742
+ }
743
+ }
744
+
707
745
static void _transfer_encoding_chunked_write_data (_In_ winhttp_request_context * p_request_context)
708
746
{
709
747
const size_t chunk_size = p_request_context->m_http_client ->client_config ().chunksize ();
@@ -751,7 +789,7 @@ class winhttp_client : public _http_client_communicator
751
789
if (!WinHttpWriteData (
752
790
p_request_context->m_request_handle ,
753
791
&p_request_context->m_body_data .get ()[offset],
754
- ( DWORD) length,
792
+ static_cast < DWORD>( length) ,
755
793
nullptr ))
756
794
{
757
795
p_request_context->report_error (GetLastError (), _XPLATSTR (" Error writing data" ));
@@ -804,7 +842,7 @@ class winhttp_client : public _http_client_communicator
804
842
if ( !WinHttpWriteData (
805
843
p_request_context->m_request_handle ,
806
844
p_request_context->m_body_data .get (),
807
- ( DWORD) to_write,
845
+ static_cast < DWORD>( to_write) ,
808
846
nullptr ))
809
847
{
810
848
p_request_context->report_error (GetLastError (), _XPLATSTR (" Error writing data" ));
@@ -846,7 +884,7 @@ class winhttp_client : public _http_client_communicator
846
884
if ( !WinHttpWriteData (
847
885
p_request_context->m_request_handle ,
848
886
p_request_context->m_body_data .get (),
849
- ( DWORD) read,
887
+ static_cast < DWORD>( read) ,
850
888
nullptr ))
851
889
{
852
890
p_request_context->report_error (GetLastError (), _XPLATSTR (" Error writing data" ));
@@ -1072,7 +1110,7 @@ class winhttp_client : public _http_client_communicator
1072
1110
auto progress = p_request_context->m_request ._get_impl ()->_progress_handler ();
1073
1111
if ( progress )
1074
1112
{
1075
- p_request_context->m_uploaded += ( size64_t ) bytesWritten;
1113
+ p_request_context->m_uploaded += bytesWritten;
1076
1114
try { (*progress)(message_direction::upload, p_request_context->m_uploaded ); } catch (...)
1077
1115
{
1078
1116
p_request_context->report_exception (std::current_exception ());
@@ -1157,11 +1195,7 @@ class winhttp_client : public _http_client_communicator
1157
1195
// If none of them is specified, the message length should be determined by the server closing the connection.
1158
1196
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4
1159
1197
1160
- // WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE callback determines whether this function was successful and the value of the parameters.
1161
- if (!WinHttpQueryDataAvailable (hRequestHandle, nullptr ))
1162
- {
1163
- p_request_context->report_error (GetLastError (), _XPLATSTR (" Error querying for http body data" ));
1164
- }
1198
+ read_next_response_chunk (p_request_context, 0 , true );
1165
1199
break ;
1166
1200
}
1167
1201
case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE :
@@ -1172,16 +1206,13 @@ class winhttp_client : public _http_client_communicator
1172
1206
if (num_bytes > 0 )
1173
1207
{
1174
1208
auto writebuf = p_request_context->_get_writebuffer ();
1175
- if ( !_check_streambuf (p_request_context, writebuf, _XPLATSTR (" Output stream is not open" )) )
1176
- break ;
1177
-
1178
1209
p_request_context->allocate_reply_space (writebuf.alloc (num_bytes), num_bytes);
1179
1210
1180
1211
// Read in body all at once.
1181
1212
if (!WinHttpReadData (
1182
1213
hRequestHandle,
1183
- (LPVOID) p_request_context->m_body_data .get (),
1184
- (DWORD) num_bytes,
1214
+ p_request_context->m_body_data .get (),
1215
+ num_bytes,
1185
1216
nullptr ))
1186
1217
{
1187
1218
p_request_context->report_error (GetLastError (), _XPLATSTR (" Error receiving http body chunk" ));
@@ -1201,75 +1232,65 @@ class winhttp_client : public _http_client_communicator
1201
1232
}
1202
1233
}
1203
1234
1204
- p_request_context->complete_request (( size_t ) p_request_context->m_downloaded );
1235
+ p_request_context->complete_request (p_request_context->m_downloaded );
1205
1236
}
1206
1237
break ;
1207
1238
}
1208
1239
case WINHTTP_CALLBACK_STATUS_READ_COMPLETE :
1209
1240
{
1210
1241
// Status information length contains the number of bytes read.
1211
- // WinHTTP will always fill the whole buffer or read nothing.
1212
- // If number of bytes read is zero than we have reached the end.
1242
+ const DWORD bytesRead = statusInfoLength;
1213
1243
1214
- if (statusInfoLength > 0 )
1244
+ // Report progress about downloaded bytes.
1245
+ auto progress = p_request_context->m_request ._get_impl ()->_progress_handler ();
1246
+ p_request_context->m_downloaded += statusInfoLength;
1247
+ if (progress)
1215
1248
{
1216
- auto progress = p_request_context->m_request ._get_impl ()->_progress_handler ();
1217
- p_request_context->m_downloaded += (size64_t )statusInfoLength;
1218
- if ( progress )
1249
+ try { (*progress)(message_direction::download, p_request_context->m_downloaded ); }
1250
+ catch (...)
1219
1251
{
1220
- try { (*progress)(message_direction::download, p_request_context->m_downloaded ); } catch (...)
1252
+ p_request_context->report_exception (std::current_exception ());
1253
+ return ;
1254
+ }
1255
+ }
1256
+
1257
+ // If no bytes have been read, then this is the end of the response.
1258
+ if (bytesRead == 0 )
1259
+ {
1260
+ p_request_context->complete_request (p_request_context->m_downloaded );
1261
+ break ;
1262
+ }
1263
+
1264
+ // If the data was allocated directly from the buffer then commit, otherwise we still
1265
+ // need to write to the response stream buffer.
1266
+ auto writebuf = p_request_context->_get_writebuffer ();
1267
+ if (p_request_context->is_externally_allocated ())
1268
+ {
1269
+ writebuf.commit (bytesRead);
1270
+ read_next_response_chunk (p_request_context, bytesRead);
1271
+ }
1272
+ else
1273
+ {
1274
+ writebuf.putn (p_request_context->m_body_data .get (), bytesRead).then (
1275
+ [hRequestHandle, p_request_context, bytesRead] (pplx::task<size_t > op)
1276
+ {
1277
+ size_t written = 0 ;
1278
+ try { written = op.get (); }
1279
+ catch (...)
1221
1280
{
1222
1281
p_request_context->report_exception (std::current_exception ());
1223
1282
return ;
1224
1283
}
1225
- }
1226
-
1227
- auto writebuf = p_request_context->_get_writebuffer ();
1228
-
1229
- if ( p_request_context->is_externally_allocated () )
1230
- {
1231
- writebuf.commit (statusInfoLength);
1232
1284
1233
- // Look for more data
1234
- if (! WinHttpQueryDataAvailable (hRequestHandle, nullptr ) )
1285
+ // If we couldn't write everything, it's time to exit.
1286
+ if (written != bytesRead )
1235
1287
{
1236
- p_request_context->report_error ( GetLastError (), _XPLATSTR ( " Error querying for http body chunk " ));
1288
+ p_request_context->report_exception ( std::runtime_error ( " response stream unexpectedly failed to write the requested number of bytes " ));
1237
1289
return ;
1238
1290
}
1239
- }
1240
- else
1241
- {
1242
- writebuf.putn (p_request_context->m_body_data .get (), statusInfoLength).then (
1243
- [hRequestHandle, p_request_context, statusInfoLength]
1244
- (pplx::task<size_t > op)
1245
- {
1246
- size_t written = 0 ;
1247
- try { written = op.get (); } catch (...)
1248
- {
1249
- p_request_context->report_exception (std::current_exception ());
1250
- return ;
1251
- }
1252
-
1253
- // If we couldn't write everything, it's time to exit.
1254
- if ( written != statusInfoLength )
1255
- {
1256
- p_request_context->report_exception (std::runtime_error (" response stream unexpectedly failed to write the requested number of bytes" ));
1257
- return ;
1258
- }
1259
-
1260
- // Look for more data
1261
- if (!WinHttpQueryDataAvailable (hRequestHandle, nullptr ))
1262
- {
1263
- p_request_context->report_error (GetLastError (), _XPLATSTR (" Error querying for http body chunk" ));
1264
- return ;
1265
- }
1266
- });
1267
- }
1268
- }
1269
- else
1270
- {
1271
- // Done reading so set task completion event and close the request handle.
1272
- p_request_context->complete_request ((size_t )p_request_context->m_downloaded );
1291
+
1292
+ read_next_response_chunk (p_request_context, bytesRead);
1293
+ });
1273
1294
}
1274
1295
break ;
1275
1296
}
0 commit comments