@@ -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;
@@ -301,7 +300,10 @@ namespace web { namespace http
301
300
}
302
301
}
303
302
304
- linux_client_request_context (std::shared_ptr<_http_client_communicator> &client, http_request request, std::shared_ptr<linux_connection> connection);
303
+ linux_client_request_context (
304
+ const std::shared_ptr<_http_client_communicator> &client,
305
+ http_request request,
306
+ const std::shared_ptr<linux_connection> &connection);
305
307
306
308
protected:
307
309
virtual void cleanup ()
@@ -378,34 +380,16 @@ namespace web { namespace http
378
380
if (ctx->m_request .headers ().match (header_names::transfer_encoding, transferencoding) && transferencoding == " chunked" )
379
381
{
380
382
ctx->m_needChunked = true ;
381
- }
382
-
383
- bool has_body;
384
-
385
- if (ctx->m_request .headers ().match (header_names::content_length, ctx->m_known_size ))
386
- {
387
- // Have request body if content length header field is non-zero.
388
- has_body = (0 != ctx->m_known_size );
389
- }
390
- else
383
+ }
384
+ else if (!ctx->m_request .headers ().match (header_names::content_length, ctx->m_known_size ))
391
385
{
392
- // Stream without content length is the signal of requiring transcoding .
386
+ // Stream without content length is the signal of requiring transfer encoding chunked .
393
387
if (ctx->m_request .body ())
394
388
{
395
- has_body = true ;
396
389
ctx->m_needChunked = true ;
397
390
extra_headers.append (header_names::transfer_encoding);
398
391
extra_headers.append (" :chunked" + CRLF);
399
392
}
400
- else
401
- {
402
- has_body = false ;
403
- }
404
- }
405
-
406
- if (has_body && !_check_streambuf (ctx, ctx->_get_readbuffer (), " Input stream is not open" ))
407
- {
408
- return ;
409
393
}
410
394
411
395
request_stream << flatten_http_headers (ctx->m_request .headers ());
@@ -425,7 +409,6 @@ namespace web { namespace http
425
409
// If the connection is new (unresolved and unconnected socket), then start async
426
410
// call to resolve first, leading eventually to request write.
427
411
tcp::resolver::query query (host, utility::conversions::print_string (port));
428
-
429
412
m_resolver.async_resolve (query, boost::bind (&linux_client::handle_resolve, shared_from_this (), boost::asio::placeholders::error, boost::asio::placeholders::iterator, ctx));
430
413
}
431
414
@@ -453,23 +436,6 @@ namespace web { namespace http
453
436
454
437
private:
455
438
tcp::resolver m_resolver;
456
-
457
- static bool _check_streambuf (std::shared_ptr<linux_client_request_context> ctx, concurrency::streams::streambuf<uint8_t > rdbuf, const utility::char_t * msg)
458
- {
459
- if (!rdbuf.is_open ())
460
- {
461
- auto eptr = rdbuf.exception ();
462
- if (!(eptr == nullptr ))
463
- {
464
- ctx->report_exception (eptr);
465
- }
466
- else
467
- {
468
- ctx->report_exception (http_exception (msg));
469
- }
470
- }
471
- return rdbuf.is_open ();
472
- }
473
439
474
440
// Helper function to create ssl stream and set verification options.
475
441
void reset_ssl_stream (const std::shared_ptr<linux_client_request_context> &ctx)
@@ -507,15 +473,15 @@ namespace web { namespace http
507
473
}
508
474
}
509
475
510
- void write_request (std::shared_ptr<linux_client_request_context> ctx)
476
+ void write_request (const std::shared_ptr<linux_client_request_context> & ctx)
511
477
{
512
478
if (ctx->m_ssl_stream )
513
479
{
514
480
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));
515
481
}
516
482
else
517
483
{
518
- 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));
484
+ 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));
519
485
}
520
486
}
521
487
@@ -618,7 +584,7 @@ namespace web { namespace http
618
584
{
619
585
if (!ec)
620
586
{
621
- 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));
587
+ 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));
622
588
}
623
589
else
624
590
{
@@ -630,6 +596,7 @@ namespace web { namespace http
630
596
{
631
597
if (ec)
632
598
{
599
+ // Reuse error handling.
633
600
return handle_write_body (ec, ctx);
634
601
}
635
602
@@ -647,9 +614,10 @@ namespace web { namespace http
647
614
}
648
615
}
649
616
617
+ const auto & chunkSize = client_config ().chunksize ();
650
618
auto readbuf = ctx->_get_readbuffer ();
651
- uint8_t *buf = boost::asio::buffer_cast<uint8_t *>(ctx->m_body_buf .prepare (client_config (). chunksize () + http::details::chunked_encoding::additional_encoding_space));
652
- readbuf.getn (buf + http::details::chunked_encoding::data_offset, client_config (). chunksize () )
619
+ uint8_t *buf = boost::asio::buffer_cast<uint8_t *>(ctx->m_body_buf .prepare (chunkSize + http::details::chunked_encoding::additional_encoding_space));
620
+ readbuf.getn (buf + http::details::chunked_encoding::data_offset, chunkSize )
653
621
.then ([=](pplx::task<size_t > op)
654
622
{
655
623
size_t readSize = 0 ;
@@ -662,11 +630,11 @@ namespace web { namespace http
662
630
ctx->report_exception (std::current_exception ());
663
631
return ;
664
632
}
665
- const size_t offset = http::details::chunked_encoding::add_chunked_delimiters (buf, client_config ().chunksize () + http::details::chunked_encoding::additional_encoding_space, readSize);
633
+
634
+ const size_t offset = http::details::chunked_encoding::add_chunked_delimiters (buf, chunkSize + http::details::chunked_encoding::additional_encoding_space, readSize);
666
635
ctx->m_body_buf .commit (readSize + http::details::chunked_encoding::additional_encoding_space);
667
636
ctx->m_body_buf .consume (offset);
668
- ctx->m_current_size += readSize;
669
- ctx->m_uploaded += (size64_t )readSize;
637
+ ctx->m_uploaded += static_cast <uint64_t >(readSize);
670
638
if (ctx->m_ssl_stream )
671
639
{
672
640
if (readSize != 0 )
@@ -698,8 +666,9 @@ namespace web { namespace http
698
666
699
667
void handle_write_large_body (const boost::system::error_code& ec, std::shared_ptr<linux_client_request_context> ctx)
700
668
{
701
- if (ec || ctx->m_current_size >= ctx->m_known_size )
669
+ if (ec || ctx->m_uploaded >= ctx->m_known_size )
702
670
{
671
+ // Reuse error handling.
703
672
return handle_write_body (ec, ctx);
704
673
}
705
674
@@ -717,25 +686,10 @@ namespace web { namespace http
717
686
}
718
687
}
719
688
720
- auto readbuf = ctx->_get_readbuffer ();
721
- const size_t readSize = std::min (client_config ().chunksize (), ctx->m_known_size - ctx->m_current_size );
722
-
723
- readbuf.getn (boost::asio::buffer_cast<uint8_t *>(ctx->m_body_buf .prepare (readSize)), readSize)
724
- .then ([=](pplx::task<size_t > op)
689
+ auto write_chunk = [=](size_t chunkSize)
725
690
{
726
- size_t actualSize = 0 ;
727
- try
728
- {
729
- actualSize = op.get ();
730
- }
731
- catch (...)
732
- {
733
- ctx->report_exception (std::current_exception ());
734
- return ;
735
- }
736
- ctx->m_uploaded += (size64_t )actualSize;
737
- ctx->m_current_size += actualSize;
738
- ctx->m_body_buf .commit (actualSize);
691
+ ctx->m_uploaded += static_cast <uint64_t >(chunkSize);
692
+ ctx->m_body_buf .commit (chunkSize);
739
693
740
694
if (ctx->m_ssl_stream )
741
695
{
@@ -747,15 +701,34 @@ namespace web { namespace http
747
701
boost::asio::async_write (ctx->m_connection ->socket (), ctx->m_body_buf ,
748
702
boost::bind (&linux_client::handle_write_large_body, shared_from_this (), boost::asio::placeholders::error, ctx));
749
703
}
704
+ };
705
+
706
+ const auto readSize = static_cast <size_t >(std::min (static_cast <uint64_t >(client_config ().chunksize ()), ctx->m_known_size - ctx->m_uploaded ));
707
+
708
+ auto readbuf = ctx->_get_readbuffer ();
709
+ readbuf.getn (boost::asio::buffer_cast<uint8_t *>(ctx->m_body_buf .prepare (readSize)), readSize)
710
+ .then ([=](pplx::task<size_t > op)
711
+ {
712
+ try
713
+ {
714
+ write_chunk (op.get ());
715
+ }
716
+ catch (...)
717
+ {
718
+ ctx->report_exception (std::current_exception ());
719
+ return ;
720
+ }
750
721
});
751
722
}
752
723
753
- void handle_write_request (const boost::system::error_code& ec, std::shared_ptr<linux_client_request_context> ctx)
724
+ void handle_write_headers (const boost::system::error_code& ec, std::shared_ptr<linux_client_request_context> ctx)
754
725
{
755
- if (!ec)
726
+ if (ec)
727
+ {
728
+ ctx->report_error (" Failed to write request headers" , ec, httpclient_errorcode_context::writeheader);
729
+ }
730
+ else
756
731
{
757
- ctx->m_current_size = 0 ;
758
-
759
732
if (ctx->m_needChunked )
760
733
{
761
734
handle_write_chunked_body (ec, ctx);
@@ -765,10 +738,6 @@ namespace web { namespace http
765
738
handle_write_large_body (ec, ctx);
766
739
}
767
740
}
768
- else
769
- {
770
- ctx->report_error (" Failed to write request headers" , ec, httpclient_errorcode_context::writeheader);
771
- }
772
741
}
773
742
774
743
void handle_write_body (const boost::system::error_code& ec, std::shared_ptr<linux_client_request_context> ctx)
@@ -865,9 +834,9 @@ namespace web { namespace http
865
834
}
866
835
}
867
836
868
- void read_headers (std::shared_ptr<linux_client_request_context> ctx)
837
+ void read_headers (const std::shared_ptr<linux_client_request_context> & ctx)
869
838
{
870
- ctx-> m_needChunked = false ;
839
+ auto needChunked = false ;
871
840
std::istream response_stream (&ctx->m_body_buf );
872
841
std::string header;
873
842
while (std::getline (response_stream, header) && header != " \r " )
@@ -882,7 +851,7 @@ namespace web { namespace http
882
851
883
852
if (boost::iequals (name, header_names::transfer_encoding))
884
853
{
885
- ctx-> m_needChunked = boost::iequals (value, U (" chunked" ));
854
+ needChunked = boost::iequals (value, U (" chunked" ));
886
855
}
887
856
888
857
if (boost::iequals (name, header_names::connection))
@@ -904,7 +873,7 @@ namespace web { namespace http
904
873
905
874
// note: need to check for 'chunked' here as well, azure storage sends both
906
875
// transfer-encoding:chunked and content-length:0 (although HTTP says not to)
907
- if (ctx->m_request .method () == U (" HEAD" ) || (!ctx-> m_needChunked && ctx->m_known_size == 0 ))
876
+ if (ctx->m_request .method () == U (" HEAD" ) || (!needChunked && ctx->m_known_size == 0 ))
908
877
{
909
878
// we can stop early - no body
910
879
auto progress = ctx->m_request ._get_impl ()->_progress_handler ();
@@ -925,10 +894,9 @@ namespace web { namespace http
925
894
}
926
895
else
927
896
{
928
- ctx->m_current_size = 0 ;
929
- if (!ctx->m_needChunked )
897
+ if (!needChunked)
930
898
{
931
- async_read_until_buffersize (std::min (ctx->m_known_size , client_config ().chunksize ()),
899
+ async_read_until_buffersize (static_cast < size_t >( std::min (ctx->m_known_size , static_cast < uint64_t >( client_config ().chunksize ()) )),
932
900
boost::bind (&linux_client::handle_read_content, shared_from_this (), boost::asio::placeholders::error, ctx), ctx);
933
901
}
934
902
else
@@ -998,8 +966,7 @@ namespace web { namespace http
998
966
{
999
967
if (!ec)
1000
968
{
1001
- ctx->m_current_size += to_read;
1002
- ctx->m_downloaded += (size64_t )to_read;
969
+ ctx->m_downloaded += static_cast <uint64_t >(to_read);
1003
970
auto progress = ctx->m_request ._get_impl ()->_progress_handler ();
1004
971
if (progress)
1005
972
{
@@ -1023,7 +990,7 @@ namespace web { namespace http
1023
990
try
1024
991
{
1025
992
op.wait ();
1026
- ctx->complete_request (ctx->m_current_size );
993
+ ctx->complete_request (ctx->m_downloaded );
1027
994
}
1028
995
catch (...)
1029
996
{
@@ -1077,7 +1044,7 @@ namespace web { namespace http
1077
1044
{
1078
1045
if (ec == boost::asio::error::eof && ctx->m_known_size == std::numeric_limits<size_t >::max ())
1079
1046
{
1080
- ctx->m_known_size = ctx->m_current_size + ctx->m_body_buf .size ();
1047
+ ctx->m_known_size = ctx->m_downloaded + ctx->m_body_buf .size ();
1081
1048
}
1082
1049
else
1083
1050
{
@@ -1100,24 +1067,23 @@ namespace web { namespace http
1100
1067
}
1101
1068
}
1102
1069
1103
- if (ctx->m_current_size < ctx->m_known_size )
1070
+ if (ctx->m_downloaded < ctx->m_known_size )
1104
1071
{
1105
1072
ctx->reset_timer (static_cast <int >(client_config ().timeout ().count ()));
1106
1073
1107
1074
// more data need to be read
1108
1075
writeBuffer.putn (boost::asio::buffer_cast<const uint8_t *>(ctx->m_body_buf .data ()),
1109
- std::min (ctx->m_body_buf .size (), ctx->m_known_size - ctx->m_current_size ))
1076
+ static_cast < size_t >( std::min (static_cast < uint64_t >( ctx->m_body_buf .size ()) , ctx->m_known_size - ctx->m_downloaded ) ))
1110
1077
.then ([=](pplx::task<size_t > op)
1111
1078
{
1112
1079
size_t writtenSize = 0 ;
1113
1080
try
1114
1081
{
1115
1082
writtenSize = op.get ();
1116
- ctx->m_downloaded += (size64_t )writtenSize;
1117
- ctx->m_current_size += writtenSize;
1083
+ ctx->m_downloaded += static_cast <uint64_t >(writtenSize);
1118
1084
ctx->m_body_buf .consume (writtenSize);
1119
1085
1120
- async_read_until_buffersize (std::min (client_config ().chunksize (), ctx->m_known_size - ctx->m_current_size ),
1086
+ async_read_until_buffersize (static_cast < size_t >( std::min (static_cast < uint64_t >( client_config ().chunksize ()) , ctx->m_known_size - ctx->m_downloaded ) ),
1121
1087
boost::bind (&linux_client::handle_read_content, shared_from_this (), boost::asio::placeholders::error, ctx), ctx);
1122
1088
}
1123
1089
catch (...)
@@ -1129,13 +1095,12 @@ namespace web { namespace http
1129
1095
}
1130
1096
else
1131
1097
{
1132
- writeBuffer.sync ()
1133
- .then ([ctx](pplx::task<void > op)
1098
+ writeBuffer.sync ().then ([ctx](pplx::task<void > op)
1134
1099
{
1135
1100
try
1136
1101
{
1137
1102
op.wait ();
1138
- ctx->complete_request (ctx->m_current_size );
1103
+ ctx->complete_request (ctx->m_downloaded );
1139
1104
}
1140
1105
catch (...)
1141
1106
{
@@ -1164,16 +1129,15 @@ namespace web { namespace http
1164
1129
}
1165
1130
1166
1131
linux_client_request_context::linux_client_request_context (
1167
- std::shared_ptr<_http_client_communicator> &client,
1132
+ const std::shared_ptr<_http_client_communicator> &client,
1168
1133
http_request request,
1169
- std::shared_ptr<linux_connection> connection)
1134
+ const std::shared_ptr<linux_connection> & connection)
1170
1135
: request_context(client, request)
1171
1136
, m_known_size(0 )
1172
- , m_current_size(0 )
1173
1137
, m_needChunked(false )
1174
1138
, m_timedout(false )
1175
1139
, m_timeout_timer(crossplat::threadpool::shared_instance().service())
1176
- , m_connection(std::move( connection) )
1140
+ , m_connection(connection)
1177
1141
#if defined(__APPLE__) || defined(ANDROID)
1178
1142
, m_openssl_failed(false )
1179
1143
#endif
0 commit comments