@@ -274,8 +274,7 @@ namespace web { namespace http
274
274
}
275
275
276
276
std::unique_ptr<boost::asio::ssl::stream<tcp::socket &> > m_ssl_stream;
277
- size_t m_known_size;
278
- size_t m_current_size;
277
+ uint64_t m_known_size;
279
278
bool m_needChunked;
280
279
bool m_timedout;
281
280
boost::asio::streambuf m_body_buf;
@@ -377,34 +376,16 @@ namespace web { namespace http
377
376
if (ctx->m_request .headers ().match (header_names::transfer_encoding, transferencoding) && transferencoding == " chunked" )
378
377
{
379
378
ctx->m_needChunked = true ;
380
- }
381
-
382
- bool has_body;
383
-
384
- if (ctx->m_request .headers ().match (header_names::content_length, ctx->m_known_size ))
385
- {
386
- // Have request body if content length header field is non-zero.
387
- has_body = (0 != ctx->m_known_size );
388
- }
389
- else
379
+ }
380
+ else if (!ctx->m_request .headers ().match (header_names::content_length, ctx->m_known_size ))
390
381
{
391
- // Stream without content length is the signal of requiring transcoding .
382
+ // Stream without content length is the signal of requiring transfer encoding chunked .
392
383
if (ctx->m_request .body ())
393
384
{
394
- has_body = true ;
395
385
ctx->m_needChunked = true ;
396
386
extra_headers.append (header_names::transfer_encoding);
397
387
extra_headers.append (" :chunked" + CRLF);
398
388
}
399
- else
400
- {
401
- has_body = false ;
402
- }
403
- }
404
-
405
- if (has_body && !_check_streambuf (ctx, ctx->_get_readbuffer (), " Input stream is not open" ))
406
- {
407
- return ;
408
389
}
409
390
410
391
request_stream << flatten_http_headers (ctx->m_request .headers ());
@@ -424,7 +405,6 @@ namespace web { namespace http
424
405
// If the connection is new (unresolved and unconnected socket), then start async
425
406
// call to resolve first, leading eventually to request write.
426
407
tcp::resolver::query query (host, utility::conversions::print_string (port));
427
-
428
408
m_resolver.async_resolve (query, boost::bind (&linux_client::handle_resolve, shared_from_this (), boost::asio::placeholders::error, boost::asio::placeholders::iterator, ctx));
429
409
}
430
410
@@ -455,26 +435,9 @@ namespace web { namespace http
455
435
#if defined(__APPLE__) || defined(ANDROID)
456
436
bool m_openssl_failed;
457
437
#endif
458
-
459
- static bool _check_streambuf (std::shared_ptr<linux_client_request_context> ctx, concurrency::streams::streambuf<uint8_t > rdbuf, const utility::char_t * msg)
460
- {
461
- if (!rdbuf.is_open ())
462
- {
463
- auto eptr = rdbuf.exception ();
464
- if (!(eptr == nullptr ))
465
- {
466
- ctx->report_exception (eptr);
467
- }
468
- else
469
- {
470
- ctx->report_exception (http_exception (msg));
471
- }
472
- }
473
- return rdbuf.is_open ();
474
- }
475
438
476
439
// Helper function to create ssl stream and set verification options.
477
- void reset_ssl_stream (std::shared_ptr<linux_client_request_context> &ctx)
440
+ void reset_ssl_stream (const std::shared_ptr<linux_client_request_context> &ctx)
478
441
{
479
442
boost::asio::ssl::context sslContext (boost::asio::ssl::context::sslv23);
480
443
sslContext.set_default_verify_paths ();
@@ -509,15 +472,15 @@ namespace web { namespace http
509
472
}
510
473
}
511
474
512
- void write_request (std::shared_ptr<linux_client_request_context> ctx)
475
+ void write_request (std::shared_ptr<linux_client_request_context> & ctx)
513
476
{
514
477
if (ctx->m_ssl_stream )
515
478
{
516
479
ctx->m_ssl_stream ->async_handshake (boost::asio::ssl::stream_base::client, boost::bind (&linux_client::handle_handshake, shared_from_this (), boost::asio::placeholders::error, ctx));
517
480
}
518
481
else
519
482
{
520
- boost::asio::async_write (ctx->m_connection ->socket (), ctx->m_body_buf , boost::bind (&linux_client::handle_write_request , shared_from_this (), boost::asio::placeholders::error, ctx));
483
+ boost::asio::async_write (ctx->m_connection ->socket (), ctx->m_body_buf , boost::bind (&linux_client::handle_write_headers , shared_from_this (), boost::asio::placeholders::error, ctx));
521
484
}
522
485
}
523
486
@@ -617,7 +580,7 @@ namespace web { namespace http
617
580
{
618
581
if (!ec)
619
582
{
620
- boost::asio::async_write (*ctx->m_ssl_stream , ctx->m_body_buf , boost::bind (&linux_client::handle_write_request , shared_from_this (), boost::asio::placeholders::error, ctx));
583
+ boost::asio::async_write (*ctx->m_ssl_stream , ctx->m_body_buf , boost::bind (&linux_client::handle_write_headers , shared_from_this (), boost::asio::placeholders::error, ctx));
621
584
}
622
585
else
623
586
{
@@ -629,6 +592,7 @@ namespace web { namespace http
629
592
{
630
593
if (ec)
631
594
{
595
+ // Reuse error handling.
632
596
return handle_write_body (ec, ctx);
633
597
}
634
598
@@ -646,9 +610,10 @@ namespace web { namespace http
646
610
}
647
611
}
648
612
613
+ const auto & chunkSize = client_config ().chunksize ();
649
614
auto readbuf = ctx->_get_readbuffer ();
650
- uint8_t *buf = boost::asio::buffer_cast<uint8_t *>(ctx->m_body_buf .prepare (client_config (). chunksize () + http::details::chunked_encoding::additional_encoding_space));
651
- readbuf.getn (buf + http::details::chunked_encoding::data_offset, client_config (). chunksize () )
615
+ uint8_t *buf = boost::asio::buffer_cast<uint8_t *>(ctx->m_body_buf .prepare (chunkSize + http::details::chunked_encoding::additional_encoding_space));
616
+ readbuf.getn (buf + http::details::chunked_encoding::data_offset, chunkSize )
652
617
.then ([=](pplx::task<size_t > op)
653
618
{
654
619
size_t readSize = 0 ;
@@ -661,11 +626,11 @@ namespace web { namespace http
661
626
ctx->report_exception (std::current_exception ());
662
627
return ;
663
628
}
664
- const size_t offset = http::details::chunked_encoding::add_chunked_delimiters (buf, client_config ().chunksize () + http::details::chunked_encoding::additional_encoding_space, readSize);
629
+
630
+ const size_t offset = http::details::chunked_encoding::add_chunked_delimiters (buf, chunkSize + http::details::chunked_encoding::additional_encoding_space, readSize);
665
631
ctx->m_body_buf .commit (readSize + http::details::chunked_encoding::additional_encoding_space);
666
632
ctx->m_body_buf .consume (offset);
667
- ctx->m_current_size += readSize;
668
- ctx->m_uploaded += (size64_t )readSize;
633
+ ctx->m_uploaded += static_cast <uint64_t >(readSize);
669
634
if (ctx->m_ssl_stream )
670
635
{
671
636
if (readSize != 0 )
@@ -697,8 +662,9 @@ namespace web { namespace http
697
662
698
663
void handle_write_large_body (const boost::system::error_code& ec, std::shared_ptr<linux_client_request_context> ctx)
699
664
{
700
- if (ec || ctx->m_current_size >= ctx->m_known_size )
665
+ if (ec || ctx->m_uploaded >= ctx->m_known_size )
701
666
{
667
+ // Reuse error handling.
702
668
return handle_write_body (ec, ctx);
703
669
}
704
670
@@ -716,25 +682,10 @@ namespace web { namespace http
716
682
}
717
683
}
718
684
719
- auto readbuf = ctx->_get_readbuffer ();
720
- const size_t readSize = std::min (client_config ().chunksize (), ctx->m_known_size - ctx->m_current_size );
721
-
722
- readbuf.getn (boost::asio::buffer_cast<uint8_t *>(ctx->m_body_buf .prepare (readSize)), readSize)
723
- .then ([=](pplx::task<size_t > op)
685
+ auto write_chunk = [=](size_t chunkSize)
724
686
{
725
- size_t actualSize = 0 ;
726
- try
727
- {
728
- actualSize = op.get ();
729
- }
730
- catch (...)
731
- {
732
- ctx->report_exception (std::current_exception ());
733
- return ;
734
- }
735
- ctx->m_uploaded += (size64_t )actualSize;
736
- ctx->m_current_size += actualSize;
737
- ctx->m_body_buf .commit (actualSize);
687
+ ctx->m_uploaded += static_cast <uint64_t >(chunkSize);
688
+ ctx->m_body_buf .commit (chunkSize);
738
689
739
690
if (ctx->m_ssl_stream )
740
691
{
@@ -746,15 +697,34 @@ namespace web { namespace http
746
697
boost::asio::async_write (ctx->m_connection ->socket (), ctx->m_body_buf ,
747
698
boost::bind (&linux_client::handle_write_large_body, shared_from_this (), boost::asio::placeholders::error, ctx));
748
699
}
700
+ };
701
+
702
+ const size_t readSize = std::min (client_config ().chunksize (), ctx->m_known_size - ctx->m_uploaded );
703
+
704
+ auto readbuf = ctx->_get_readbuffer ();
705
+ readbuf.getn (boost::asio::buffer_cast<uint8_t *>(ctx->m_body_buf .prepare (readSize)), readSize)
706
+ .then ([=](pplx::task<size_t > op)
707
+ {
708
+ try
709
+ {
710
+ write_chunk (op.get ());
711
+ }
712
+ catch (...)
713
+ {
714
+ ctx->report_exception (std::current_exception ());
715
+ return ;
716
+ }
749
717
});
750
718
}
751
719
752
- void handle_write_request (const boost::system::error_code& ec, std::shared_ptr<linux_client_request_context> ctx)
720
+ void handle_write_headers (const boost::system::error_code& ec, std::shared_ptr<linux_client_request_context> ctx)
753
721
{
754
- if (!ec)
722
+ if (ec)
723
+ {
724
+ ctx->report_error (" Failed to write request headers" , ec, httpclient_errorcode_context::writeheader);
725
+ }
726
+ else
755
727
{
756
- ctx->m_current_size = 0 ;
757
-
758
728
if (ctx->m_needChunked )
759
729
{
760
730
handle_write_chunked_body (ec, ctx);
@@ -764,10 +734,6 @@ namespace web { namespace http
764
734
handle_write_large_body (ec, ctx);
765
735
}
766
736
}
767
- else
768
- {
769
- ctx->report_error (" Failed to write request headers" , ec, httpclient_errorcode_context::writeheader);
770
- }
771
737
}
772
738
773
739
void handle_write_body (const boost::system::error_code& ec, std::shared_ptr<linux_client_request_context> ctx)
@@ -866,7 +832,7 @@ namespace web { namespace http
866
832
867
833
void read_headers (const std::shared_ptr<linux_client_request_context> &ctx)
868
834
{
869
- ctx-> m_needChunked = false ;
835
+ auto needChunked = false ;
870
836
std::istream response_stream (&ctx->m_body_buf );
871
837
std::string header;
872
838
while (std::getline (response_stream, header) && header != " \r " )
@@ -881,7 +847,7 @@ namespace web { namespace http
881
847
882
848
if (boost::iequals (name, header_names::transfer_encoding))
883
849
{
884
- ctx-> m_needChunked = boost::iequals (value, U (" chunked" ));
850
+ needChunked = boost::iequals (value, U (" chunked" ));
885
851
}
886
852
887
853
if (boost::iequals (name, header_names::connection))
@@ -903,7 +869,7 @@ namespace web { namespace http
903
869
904
870
// note: need to check for 'chunked' here as well, azure storage sends both
905
871
// transfer-encoding:chunked and content-length:0 (although HTTP says not to)
906
- if (ctx->m_request .method () == U (" HEAD" ) || (!ctx-> m_needChunked && ctx->m_known_size == 0 ))
872
+ if (ctx->m_request .method () == U (" HEAD" ) || (!needChunked && ctx->m_known_size == 0 ))
907
873
{
908
874
// we can stop early - no body
909
875
auto progress = ctx->m_request ._get_impl ()->_progress_handler ();
@@ -924,8 +890,7 @@ namespace web { namespace http
924
890
}
925
891
else
926
892
{
927
- ctx->m_current_size = 0 ;
928
- if (!ctx->m_needChunked )
893
+ if (!needChunked)
929
894
{
930
895
async_read_until_buffersize (std::min (ctx->m_known_size , client_config ().chunksize ()),
931
896
boost::bind (&linux_client::handle_read_content, shared_from_this (), boost::asio::placeholders::error, ctx), ctx);
@@ -997,8 +962,7 @@ namespace web { namespace http
997
962
{
998
963
if (!ec)
999
964
{
1000
- ctx->m_current_size += to_read;
1001
- ctx->m_downloaded += (size64_t )to_read;
965
+ ctx->m_downloaded += static_cast <uint64_t >(to_read);
1002
966
auto progress = ctx->m_request ._get_impl ()->_progress_handler ();
1003
967
if (progress)
1004
968
{
@@ -1022,7 +986,7 @@ namespace web { namespace http
1022
986
try
1023
987
{
1024
988
op.wait ();
1025
- ctx->complete_request (ctx->m_current_size );
989
+ ctx->complete_request (ctx->m_downloaded );
1026
990
}
1027
991
catch (...)
1028
992
{
@@ -1076,7 +1040,7 @@ namespace web { namespace http
1076
1040
{
1077
1041
if (ec == boost::asio::error::eof && ctx->m_known_size == std::numeric_limits<size_t >::max ())
1078
1042
{
1079
- ctx->m_known_size = ctx->m_current_size + ctx->m_body_buf .size ();
1043
+ ctx->m_known_size = ctx->m_downloaded + ctx->m_body_buf .size ();
1080
1044
}
1081
1045
else
1082
1046
{
@@ -1099,24 +1063,23 @@ namespace web { namespace http
1099
1063
}
1100
1064
}
1101
1065
1102
- if (ctx->m_current_size < ctx->m_known_size )
1066
+ if (ctx->m_downloaded < ctx->m_known_size )
1103
1067
{
1104
1068
ctx->reset_timer (static_cast <int >(client_config ().timeout ().count ()));
1105
1069
1106
1070
// more data need to be read
1107
1071
writeBuffer.putn (boost::asio::buffer_cast<const uint8_t *>(ctx->m_body_buf .data ()),
1108
- std::min (ctx->m_body_buf .size (), ctx->m_known_size - ctx->m_current_size ))
1072
+ std::min (ctx->m_body_buf .size (), ctx->m_known_size - ctx->m_downloaded ))
1109
1073
.then ([=](pplx::task<size_t > op)
1110
1074
{
1111
1075
size_t writtenSize = 0 ;
1112
1076
try
1113
1077
{
1114
1078
writtenSize = op.get ();
1115
- ctx->m_downloaded += (size64_t )writtenSize;
1116
- ctx->m_current_size += writtenSize;
1079
+ ctx->m_downloaded += static_cast <uint64_t >(writtenSize);
1117
1080
ctx->m_body_buf .consume (writtenSize);
1118
1081
1119
- async_read_until_buffersize (std::min (client_config ().chunksize (), ctx->m_known_size - ctx->m_current_size ),
1082
+ async_read_until_buffersize (std::min (client_config ().chunksize (), ctx->m_known_size - ctx->m_downloaded ),
1120
1083
boost::bind (&linux_client::handle_read_content, shared_from_this (), boost::asio::placeholders::error, ctx), ctx);
1121
1084
}
1122
1085
catch (...)
@@ -1133,7 +1096,7 @@ namespace web { namespace http
1133
1096
try
1134
1097
{
1135
1098
op.wait ();
1136
- ctx->complete_request (ctx->m_current_size );
1099
+ ctx->complete_request (ctx->m_downloaded );
1137
1100
}
1138
1101
catch (...)
1139
1102
{
@@ -1167,7 +1130,6 @@ namespace web { namespace http
1167
1130
const std::shared_ptr<linux_connection> &connection)
1168
1131
: request_context(client, request)
1169
1132
, m_known_size(0 )
1170
- , m_current_size(0 )
1171
1133
, m_needChunked(false )
1172
1134
, m_timedout(false )
1173
1135
, m_timeout_timer(crossplat::threadpool::shared_instance().service())
0 commit comments