@@ -589,7 +589,7 @@ class winhttp_client : public _http_client_communicator
589589 if (!WinHttpAddRequestHeaders (
590590 winhttp_context->m_request_handle ,
591591 flattened_headers.c_str (),
592- ( DWORD) flattened_headers.length (),
592+ static_cast < DWORD>( flattened_headers.length () ),
593593 WINHTTP_ADDREQ_FLAG_ADD))
594594 {
595595 request->report_error (GetLastError (), _XPLATSTR (" Error adding request headers" ));
@@ -704,6 +704,44 @@ class winhttp_client : public _http_client_communicator
704704 return has_proxy_credentials || has_server_credentials;
705705 }
706706
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+
707745 static void _transfer_encoding_chunked_write_data (_In_ winhttp_request_context * p_request_context)
708746 {
709747 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
751789 if (!WinHttpWriteData (
752790 p_request_context->m_request_handle ,
753791 &p_request_context->m_body_data .get ()[offset],
754- ( DWORD) length,
792+ static_cast < DWORD>( length) ,
755793 nullptr ))
756794 {
757795 p_request_context->report_error (GetLastError (), _XPLATSTR (" Error writing data" ));
@@ -804,7 +842,7 @@ class winhttp_client : public _http_client_communicator
804842 if ( !WinHttpWriteData (
805843 p_request_context->m_request_handle ,
806844 p_request_context->m_body_data .get (),
807- ( DWORD) to_write,
845+ static_cast < DWORD>( to_write) ,
808846 nullptr ))
809847 {
810848 p_request_context->report_error (GetLastError (), _XPLATSTR (" Error writing data" ));
@@ -846,7 +884,7 @@ class winhttp_client : public _http_client_communicator
846884 if ( !WinHttpWriteData (
847885 p_request_context->m_request_handle ,
848886 p_request_context->m_body_data .get (),
849- ( DWORD) read,
887+ static_cast < DWORD>( read) ,
850888 nullptr ))
851889 {
852890 p_request_context->report_error (GetLastError (), _XPLATSTR (" Error writing data" ));
@@ -1072,7 +1110,7 @@ class winhttp_client : public _http_client_communicator
10721110 auto progress = p_request_context->m_request ._get_impl ()->_progress_handler ();
10731111 if ( progress )
10741112 {
1075- p_request_context->m_uploaded += ( size64_t ) bytesWritten;
1113+ p_request_context->m_uploaded += bytesWritten;
10761114 try { (*progress)(message_direction::upload, p_request_context->m_uploaded ); } catch (...)
10771115 {
10781116 p_request_context->report_exception (std::current_exception ());
@@ -1157,11 +1195,7 @@ class winhttp_client : public _http_client_communicator
11571195 // If none of them is specified, the message length should be determined by the server closing the connection.
11581196 // http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4
11591197
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 );
11651199 break ;
11661200 }
11671201 case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE :
@@ -1172,16 +1206,13 @@ class winhttp_client : public _http_client_communicator
11721206 if (num_bytes > 0 )
11731207 {
11741208 auto writebuf = p_request_context->_get_writebuffer ();
1175- if ( !_check_streambuf (p_request_context, writebuf, _XPLATSTR (" Output stream is not open" )) )
1176- break ;
1177-
11781209 p_request_context->allocate_reply_space (writebuf.alloc (num_bytes), num_bytes);
11791210
11801211 // Read in body all at once.
11811212 if (!WinHttpReadData (
11821213 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,
11851216 nullptr ))
11861217 {
11871218 p_request_context->report_error (GetLastError (), _XPLATSTR (" Error receiving http body chunk" ));
@@ -1201,75 +1232,65 @@ class winhttp_client : public _http_client_communicator
12011232 }
12021233 }
12031234
1204- p_request_context->complete_request (( size_t ) p_request_context->m_downloaded );
1235+ p_request_context->complete_request (p_request_context->m_downloaded );
12051236 }
12061237 break ;
12071238 }
12081239 case WINHTTP_CALLBACK_STATUS_READ_COMPLETE :
12091240 {
12101241 // 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;
12131243
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)
12151248 {
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 (...)
12191251 {
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 (...)
12211280 {
12221281 p_request_context->report_exception (std::current_exception ());
12231282 return ;
12241283 }
1225- }
1226-
1227- auto writebuf = p_request_context->_get_writebuffer ();
1228-
1229- if ( p_request_context->is_externally_allocated () )
1230- {
1231- writebuf.commit (statusInfoLength);
12321284
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 )
12351287 {
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 " ));
12371289 return ;
12381290 }
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+ });
12731294 }
12741295 break ;
12751296 }
0 commit comments