Skip to content

Commit de9daa2

Browse files
committed
Merge branch 'development' of https://git01.codeplex.com/casablanca into 4gb_file_fix
2 parents 54b8a72 + 3751cbf commit de9daa2

File tree

1 file changed

+64
-100
lines changed

1 file changed

+64
-100
lines changed

Release/src/http/client/http_linux.cpp

Lines changed: 64 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -274,8 +274,7 @@ namespace web { namespace http
274274
}
275275

276276
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;
279278
bool m_needChunked;
280279
bool m_timedout;
281280
boost::asio::streambuf m_body_buf;
@@ -301,7 +300,10 @@ namespace web { namespace http
301300
}
302301
}
303302

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);
305307

306308
protected:
307309
virtual void cleanup()
@@ -378,34 +380,16 @@ namespace web { namespace http
378380
if (ctx->m_request.headers().match(header_names::transfer_encoding, transferencoding) && transferencoding == "chunked")
379381
{
380382
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))
391385
{
392-
// Stream without content length is the signal of requiring transcoding.
386+
// Stream without content length is the signal of requiring transfer encoding chunked.
393387
if (ctx->m_request.body())
394388
{
395-
has_body = true;
396389
ctx->m_needChunked = true;
397390
extra_headers.append(header_names::transfer_encoding);
398391
extra_headers.append(":chunked" + CRLF);
399392
}
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;
409393
}
410394

411395
request_stream << flatten_http_headers(ctx->m_request.headers());
@@ -425,7 +409,6 @@ namespace web { namespace http
425409
// If the connection is new (unresolved and unconnected socket), then start async
426410
// call to resolve first, leading eventually to request write.
427411
tcp::resolver::query query(host, utility::conversions::print_string(port));
428-
429412
m_resolver.async_resolve(query, boost::bind(&linux_client::handle_resolve, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::iterator, ctx));
430413
}
431414

@@ -453,23 +436,6 @@ namespace web { namespace http
453436

454437
private:
455438
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-
}
473439

474440
// Helper function to create ssl stream and set verification options.
475441
void reset_ssl_stream(const std::shared_ptr<linux_client_request_context> &ctx)
@@ -507,15 +473,15 @@ namespace web { namespace http
507473
}
508474
}
509475

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)
511477
{
512478
if (ctx->m_ssl_stream)
513479
{
514480
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));
515481
}
516482
else
517483
{
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));
519485
}
520486
}
521487

@@ -618,7 +584,7 @@ namespace web { namespace http
618584
{
619585
if (!ec)
620586
{
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));
622588
}
623589
else
624590
{
@@ -630,6 +596,7 @@ namespace web { namespace http
630596
{
631597
if (ec)
632598
{
599+
// Reuse error handling.
633600
return handle_write_body(ec, ctx);
634601
}
635602

@@ -647,9 +614,10 @@ namespace web { namespace http
647614
}
648615
}
649616

617+
const auto & chunkSize = client_config().chunksize();
650618
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)
653621
.then([=](pplx::task<size_t> op)
654622
{
655623
size_t readSize = 0;
@@ -662,11 +630,11 @@ namespace web { namespace http
662630
ctx->report_exception(std::current_exception());
663631
return;
664632
}
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);
666635
ctx->m_body_buf.commit(readSize + http::details::chunked_encoding::additional_encoding_space);
667636
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);
670638
if (ctx->m_ssl_stream)
671639
{
672640
if (readSize != 0)
@@ -698,8 +666,9 @@ namespace web { namespace http
698666

699667
void handle_write_large_body(const boost::system::error_code& ec, std::shared_ptr<linux_client_request_context> ctx)
700668
{
701-
if (ec || ctx->m_current_size >= ctx->m_known_size)
669+
if (ec || ctx->m_uploaded >= ctx->m_known_size)
702670
{
671+
// Reuse error handling.
703672
return handle_write_body(ec, ctx);
704673
}
705674

@@ -717,25 +686,10 @@ namespace web { namespace http
717686
}
718687
}
719688

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)
725690
{
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);
739693

740694
if (ctx->m_ssl_stream)
741695
{
@@ -747,15 +701,34 @@ namespace web { namespace http
747701
boost::asio::async_write(ctx->m_connection->socket(), ctx->m_body_buf,
748702
boost::bind(&linux_client::handle_write_large_body, shared_from_this(), boost::asio::placeholders::error, ctx));
749703
}
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+
}
750721
});
751722
}
752723

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)
754725
{
755-
if (!ec)
726+
if(ec)
727+
{
728+
ctx->report_error("Failed to write request headers", ec, httpclient_errorcode_context::writeheader);
729+
}
730+
else
756731
{
757-
ctx->m_current_size = 0;
758-
759732
if (ctx->m_needChunked)
760733
{
761734
handle_write_chunked_body(ec, ctx);
@@ -765,10 +738,6 @@ namespace web { namespace http
765738
handle_write_large_body(ec, ctx);
766739
}
767740
}
768-
else
769-
{
770-
ctx->report_error("Failed to write request headers", ec, httpclient_errorcode_context::writeheader);
771-
}
772741
}
773742

774743
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
865834
}
866835
}
867836

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)
869838
{
870-
ctx->m_needChunked = false;
839+
auto needChunked = false;
871840
std::istream response_stream(&ctx->m_body_buf);
872841
std::string header;
873842
while (std::getline(response_stream, header) && header != "\r")
@@ -882,7 +851,7 @@ namespace web { namespace http
882851

883852
if (boost::iequals(name, header_names::transfer_encoding))
884853
{
885-
ctx->m_needChunked = boost::iequals(value, U("chunked"));
854+
needChunked = boost::iequals(value, U("chunked"));
886855
}
887856

888857
if (boost::iequals(name, header_names::connection))
@@ -904,7 +873,7 @@ namespace web { namespace http
904873

905874
// note: need to check for 'chunked' here as well, azure storage sends both
906875
// 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))
908877
{
909878
// we can stop early - no body
910879
auto progress = ctx->m_request._get_impl()->_progress_handler();
@@ -925,10 +894,9 @@ namespace web { namespace http
925894
}
926895
else
927896
{
928-
ctx->m_current_size = 0;
929-
if (!ctx->m_needChunked)
897+
if (!needChunked)
930898
{
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()))),
932900
boost::bind(&linux_client::handle_read_content, shared_from_this(), boost::asio::placeholders::error, ctx), ctx);
933901
}
934902
else
@@ -998,8 +966,7 @@ namespace web { namespace http
998966
{
999967
if (!ec)
1000968
{
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);
1003970
auto progress = ctx->m_request._get_impl()->_progress_handler();
1004971
if (progress)
1005972
{
@@ -1023,7 +990,7 @@ namespace web { namespace http
1023990
try
1024991
{
1025992
op.wait();
1026-
ctx->complete_request(ctx->m_current_size);
993+
ctx->complete_request(ctx->m_downloaded);
1027994
}
1028995
catch (...)
1029996
{
@@ -1077,7 +1044,7 @@ namespace web { namespace http
10771044
{
10781045
if (ec == boost::asio::error::eof && ctx->m_known_size == std::numeric_limits<size_t>::max())
10791046
{
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();
10811048
}
10821049
else
10831050
{
@@ -1100,24 +1067,23 @@ namespace web { namespace http
11001067
}
11011068
}
11021069

1103-
if (ctx->m_current_size < ctx->m_known_size)
1070+
if (ctx->m_downloaded < ctx->m_known_size)
11041071
{
11051072
ctx->reset_timer(static_cast<int>(client_config().timeout().count()));
11061073

11071074
// more data need to be read
11081075
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)))
11101077
.then([=](pplx::task<size_t> op)
11111078
{
11121079
size_t writtenSize = 0;
11131080
try
11141081
{
11151082
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);
11181084
ctx->m_body_buf.consume(writtenSize);
11191085

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)),
11211087
boost::bind(&linux_client::handle_read_content, shared_from_this(), boost::asio::placeholders::error, ctx), ctx);
11221088
}
11231089
catch (...)
@@ -1129,13 +1095,12 @@ namespace web { namespace http
11291095
}
11301096
else
11311097
{
1132-
writeBuffer.sync()
1133-
.then([ctx](pplx::task<void> op)
1098+
writeBuffer.sync().then([ctx](pplx::task<void> op)
11341099
{
11351100
try
11361101
{
11371102
op.wait();
1138-
ctx->complete_request(ctx->m_current_size);
1103+
ctx->complete_request(ctx->m_downloaded);
11391104
}
11401105
catch (...)
11411106
{
@@ -1164,16 +1129,15 @@ namespace web { namespace http
11641129
}
11651130

11661131
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,
11681133
http_request request,
1169-
std::shared_ptr<linux_connection> connection)
1134+
const std::shared_ptr<linux_connection> &connection)
11701135
: request_context(client, request)
11711136
, m_known_size(0)
1172-
, m_current_size(0)
11731137
, m_needChunked(false)
11741138
, m_timedout(false)
11751139
, m_timeout_timer(crossplat::threadpool::shared_instance().service())
1176-
, m_connection(std::move(connection))
1140+
, m_connection(connection)
11771141
#if defined(__APPLE__) || defined(ANDROID)
11781142
, m_openssl_failed(false)
11791143
#endif

0 commit comments

Comments
 (0)