Skip to content

Commit 1501266

Browse files
committed
bugfix 760544
1 parent 2980c1f commit 1501266

File tree

3 files changed

+47
-14
lines changed

3 files changed

+47
-14
lines changed

Release/include/cpprest/http_linux_server.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ class connection
100100
template <typename ReadHandler>
101101
void async_read_until_buffersize(size_t size, ReadHandler handler);
102102
void async_process_response(http_response response);
103+
void cancel_sending_response_with_error(http_response response, std::exception_ptr);
103104
void handle_headers_written(http_response response, const boost::system::error_code& ec);
104105
void handle_write_large_response(http_response response, const boost::system::error_code& ec);
105106
void handle_write_chunked_response(http_response response, const boost::system::error_code& ec);

Release/src/http/listener/http_linux_server.cpp

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ void connection::handle_http_line(const boost::system::error_code& ec)
114114
}
115115
else
116116
{
117-
m_request.reply(status_codes::InternalError);
117+
m_request.reply(status_codes::BadRequest);
118118
do_response();
119119
}
120120
}
@@ -252,7 +252,13 @@ void connection::handle_chunked_body(const boost::system::error_code& ec, int to
252252
if (!ec)
253253
{
254254
auto writebuf = m_request._get_impl()->outstream().streambuf();
255-
writebuf.putn(buffer_cast<const uint8_t *>(m_request_buf.data()), toWrite).then([=](size_t) {
255+
writebuf.putn(buffer_cast<const uint8_t *>(m_request_buf.data()), toWrite).then([=](pplx::task<size_t> writeChunkTask) {
256+
try {
257+
writeChunkTask.get();
258+
} catch (...) {
259+
m_request._reply_if_not_already(status_codes::InternalError);
260+
return;
261+
}
256262
m_request_buf.consume(2 + toWrite);
257263

258264
boost::asio::async_read_until(*m_socket, m_request_buf, CRLF,
@@ -275,7 +281,14 @@ void connection::handle_body(const boost::system::error_code& ec)
275281
else if (m_read < m_read_size) // there is more to read
276282
{
277283
auto writebuf = m_request._get_impl()->outstream().streambuf();
278-
writebuf.putn(boost::asio::buffer_cast<const uint8_t*>(m_request_buf.data()), std::min(m_request_buf.size(), m_read_size - m_read)).then([=](size_t writtenSize) {
284+
writebuf.putn(boost::asio::buffer_cast<const uint8_t*>(m_request_buf.data()), std::min(m_request_buf.size(), m_read_size - m_read)).then([=](pplx::task<size_t> writtenSizeTask) {
285+
size_t writtenSize = 0;
286+
try {
287+
writtenSize = writtenSizeTask.get();
288+
} catch (...) {
289+
m_request._reply_if_not_already(status_codes::InternalError);
290+
return;
291+
}
279292
m_read += writtenSize;
280293
m_request_buf.consume(writtenSize);
281294
async_read_until_buffersize(std::min(ChunkSize, m_read_size - m_read), boost::bind(&connection::handle_body, this, placeholders::error));
@@ -457,16 +470,33 @@ void connection::async_process_response(http_response response)
457470
boost::asio::async_write(*m_socket, m_response_buf, boost::bind(&connection::handle_headers_written, this, response, placeholders::error));
458471
}
459472

473+
void connection::cancel_sending_response_with_error(http_response response, std::exception_ptr eptr)
474+
{
475+
auto * context = static_cast<linux_request_context*>(response._get_server_context());
476+
context->m_response_completed.set_exception(eptr);
477+
// always terminate the connection since error happens
478+
finish_request_response();
479+
}
480+
460481

461482
void connection::handle_write_chunked_response(http_response response, const boost::system::error_code& ec)
462483
{
463484
if (ec)
464485
return handle_response_written(response, ec);
465486

466487
auto readbuf = response._get_impl()->instream().streambuf();
488+
if (readbuf.is_eof())
489+
return cancel_sending_response_with_error(response, std::make_exception_ptr(http_exception("Response stream close early!")));
467490
auto membuf = m_response_buf.prepare(ChunkSize + http::details::chunked_encoding::additional_encoding_space);
468491

469-
readbuf.getn(buffer_cast<uint8_t *>(membuf) + http::details::chunked_encoding::data_offset, ChunkSize).then([=](size_t actualSize) {
492+
readbuf.getn(buffer_cast<uint8_t *>(membuf) + http::details::chunked_encoding::data_offset, ChunkSize).then([=](pplx::task<size_t> actualSizeTask) {
493+
494+
size_t actualSize = 0;
495+
try {
496+
actualSize = actualSizeTask.get();
497+
} catch (...) {
498+
return cancel_sending_response_with_error(response, std::current_exception());
499+
}
470500
size_t offset = http::details::chunked_encoding::add_chunked_delimiters(buffer_cast<uint8_t *>(membuf), ChunkSize+http::details::chunked_encoding::additional_encoding_space, actualSize);
471501
m_response_buf.commit(actualSize + http::details::chunked_encoding::additional_encoding_space);
472502
m_response_buf.consume(offset);
@@ -482,8 +512,16 @@ void connection::handle_write_large_response(http_response response, const boost
482512
return handle_response_written(response, ec);
483513

484514
auto readbuf = response._get_impl()->instream().streambuf();
515+
if (readbuf.is_eof())
516+
return cancel_sending_response_with_error(response, std::make_exception_ptr(http_exception("Response stream close early!")));
485517
size_t readBytes = std::min(ChunkSize, m_write_size - m_write);
486-
readbuf.getn(buffer_cast<uint8_t *>(m_response_buf.prepare(readBytes)), readBytes).then([=](size_t actualSize) {
518+
readbuf.getn(buffer_cast<uint8_t *>(m_response_buf.prepare(readBytes)), readBytes).then([=](pplx::task<size_t> actualSizeTask) {
519+
size_t actualSize = 0;
520+
try {
521+
actualSize = actualSizeTask.get();
522+
} catch (...) {
523+
return cancel_sending_response_with_error(response, std::current_exception());
524+
}
487525
m_write += actualSize;
488526
m_response_buf.commit(actualSize);
489527
boost::asio::async_write(*m_socket, m_response_buf, boost::bind(&connection::handle_write_large_response, this, response, placeholders::error));
@@ -494,9 +532,7 @@ void connection::handle_headers_written(http_response response, const boost::sys
494532
{
495533
if (ec)
496534
{
497-
auto * context = static_cast<linux_request_context*>(response._get_server_context());
498-
context->m_response_completed.set_exception(std::runtime_error("error writing headers"));
499-
finish_request_response();
535+
return cancel_sending_response_with_error(response, std::make_exception_ptr(http_exception("error writing headers")));
500536
}
501537
else
502538
{
@@ -512,9 +548,7 @@ void connection::handle_response_written(http_response response, const boost::sy
512548
auto * context = static_cast<linux_request_context*>(response._get_server_context());
513549
if (ec)
514550
{
515-
//printf("-> boost::system::error_code %d in handle_response_written\n", ec.value());
516-
context->m_response_completed.set_exception(std::runtime_error("error writing response"));
517-
finish_request_response();
551+
return cancel_sending_response_with_error(response, std::make_exception_ptr(http_exception("error writing response")));
518552
}
519553
else
520554
{
@@ -532,7 +566,6 @@ void connection::handle_response_written(http_response response, const boost::sy
532566

533567
void connection::finish_request_response()
534568
{
535-
//usleep(100000);
536569
// kill the connection
537570
{
538571
pplx::scoped_lock<pplx::extensibility::recursive_lock_t> lock(m_p_parent->m_connections_lock);
@@ -548,7 +581,6 @@ void connection::finish_request_response()
548581

549582
void hostport_listener::stop()
550583
{
551-
552584
// halt existing connections
553585
{
554586
pplx::scoped_lock<pplx::extensibility::recursive_lock_t> lock(m_connections_lock);

Release/tests/Functional/http/listener/connections_and_errors.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ static void close_stream_early_with_length_impl(const uri &u, bool useException)
194194
listener.close().wait();
195195
}
196196

197-
TEST_FIXTURE(uri_address, close_stream_early_with_length, "Ignore:Linux", "760544")
197+
TEST_FIXTURE(uri_address, close_stream_early_with_length)
198198
{
199199
close_stream_early_with_length_impl(m_uri, true);
200200
close_stream_early_with_length_impl(m_uri, false);

0 commit comments

Comments
 (0)