Skip to content

Commit 94ab404

Browse files
tboundy-trimblegigaplex
authored andcommitted
Fix a couple of race conditions, and use enum instead of bool
1 parent 0292c7c commit 94ab404

File tree

2 files changed

+30
-19
lines changed

2 files changed

+30
-19
lines changed

Release/include/cpprest/details/http_server_httpsys.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,13 @@ struct windows_request_context : http::details::_http_server_context
9999
// Dispatch request to the provided http_listener.
100100
void dispatch_request_to_listener(_In_ web::http::experimental::listener::details::http_listener_impl *pListener);
101101

102-
// Initialise the response task callbacks
103-
void do_response(bool bad_request);
102+
enum ShouldWaitForBody
103+
{
104+
WaitForBody,
105+
DontWaitForBody
106+
};
107+
// Initialise the response task callbacks. If the body has been requested, we should wait for it to avoid race conditions.
108+
void init_response_callbacks(ShouldWaitForBody shouldWait);
104109

105110
// Read in a portion of the request body.
106111
void read_request_body_chunk();

Release/src/http/listener/http_server_httpsys.cpp

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,7 @@ void windows_request_context::async_process_request(HTTP_REQUEST_ID request_id,
536536
{
537537
CancelThreadpoolIo(pServer->m_threadpool_io);
538538
m_msg.reply(status_codes::InternalError);
539-
do_response(true);
539+
init_response_callbacks(DontWaitForBody);
540540
}
541541
}
542542

@@ -548,7 +548,7 @@ void windows_request_context::read_headers_io_completion(DWORD error_code, DWORD
548548
if(error_code != NO_ERROR)
549549
{
550550
m_msg.reply(status_codes::InternalError);
551-
do_response(true);
551+
init_response_callbacks(DontWaitForBody);
552552
}
553553
else
554554
{
@@ -582,7 +582,9 @@ void windows_request_context::read_headers_io_completion(DWORD error_code, DWORD
582582
else
583583
{
584584
m_msg.reply(status_codes::BadRequest, badRequestMsg);
585-
do_response(true);
585+
586+
// Even though we have a bad request, we should wait for the body otherwise we risk racing over m_overlapped
587+
init_response_callbacks(WaitForBody);
586588
}
587589
}
588590
}
@@ -623,7 +625,6 @@ void windows_request_context::read_request_body_chunk()
623625
else
624626
{
625627
m_msg._get_impl()->_complete(0, std::make_exception_ptr(http_exception(error_code)));
626-
m_msg._reply_if_not_already(status_codes::InternalError);
627628
}
628629
}
629630
}
@@ -649,7 +650,6 @@ void windows_request_context::read_body_io_completion(DWORD error_code, DWORD by
649650
{
650651
request_body_buf.commit(0);
651652
m_msg._get_impl()->_complete(0, std::make_exception_ptr(http_exception(error_code)));
652-
m_msg._reply_if_not_already(status_codes::InternalError);
653653
}
654654
}
655655

@@ -660,7 +660,7 @@ void windows_request_context::dispatch_request_to_listener(_In_ web::http::exper
660660
// Save http_request copy to dispatch to user's handler in case content_ready() completes before.
661661
http_request request = m_msg;
662662

663-
do_response(false);
663+
init_response_callbacks(WaitForBody);
664664

665665
// Look up the lock for the http_listener.
666666
auto *pServer = static_cast<http_windows_server *>(http_server_api::server_api());
@@ -693,7 +693,7 @@ void windows_request_context::dispatch_request_to_listener(_In_ web::http::exper
693693
}
694694
}
695695

696-
void windows_request_context::do_response(bool bad_request)
696+
void windows_request_context::init_response_callbacks(ShouldWaitForBody shouldWait)
697697
{
698698
// Use a proxy event so we're not causing a circular reference between the http_request and the response task
699699
pplx::task_completion_event<void> proxy_content_ready;
@@ -722,7 +722,7 @@ void windows_request_context::do_response(bool bad_request)
722722
proxy_content_ready.set();
723723
});
724724

725-
get_response_task.then([this, bad_request, proxy_content_ready](pplx::task<http::http_response> responseTask)
725+
get_response_task.then([this, proxy_content_ready](pplx::task<http::http_response> responseTask)
726726
{
727727
// Don't let an exception from sending the response bring down the server.
728728
try
@@ -741,19 +741,25 @@ void windows_request_context::do_response(bool bad_request)
741741
m_response = http::http_response(status_codes::InternalError);
742742
}
743743

744-
if (bad_request)
745-
{
746-
async_process_response();
747-
}
748-
else
744+
// Wait until the content download finished before replying because m_overlapped is reused,
745+
// and we don't want to delete 'this' if the body is still downloading
746+
pplx::create_task(proxy_content_ready).then([this](pplx::task<void> t)
749747
{
750-
// Wait until the content download finished before replying.
751-
pplx::create_task(proxy_content_ready).then([this](pplx::task<void> requestBody)
748+
try
752749
{
750+
t.wait();
753751
async_process_response();
754-
});
755-
}
752+
}
753+
catch (...)
754+
{
755+
}
756+
}).wait();
756757
});
758+
759+
if (shouldWait == DontWaitForBody)
760+
{
761+
proxy_content_ready.set();
762+
}
757763
}
758764

759765
void windows_request_context::async_process_response()

0 commit comments

Comments
 (0)