Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions sdk/core/azure-core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

### Bugs Fixed

- Fixed and issue where WinHttp transport was not closing correctly in case of request timeout.

### Other Changes

- Move the connection back to the connection pool when HTTP error 404 was received. This may improve the performance of a multithreaded application when libcurl transport adapter is being used. (A community contribution, courtesy of _[mchelnokov](https://github.com/mchelnokov)_)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ namespace Azure { namespace Core { namespace Http { namespace _detail {
WinHttpTransportOptions const& options);

~WinHttpRequest();

void MarkRequestHandleClosed() { m_requestHandleClosed = true; };
void Upload(Azure::Core::Http::Request& request, Azure::Core::Context const& context);
void SendRequest(Azure::Core::Http::Request& request, Azure::Core::Context const& context);
void ReceiveResponse(Azure::Core::Context const& context);
Expand Down
26 changes: 17 additions & 9 deletions sdk/core/azure-core/src/http/winhttp/win_http_transport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -522,13 +522,21 @@ namespace Azure { namespace Core { namespace Http { namespace _detail {
}
void WinHttpAction::CompleteActionWithError(DWORD_PTR stowedErrorInformation, DWORD stowedError)
{
// Note that the order of scope_exit and lock is important - this ensures that scope_exit is
// destroyed *after* lock is destroyed, ensuring that the event is not set to the signalled
// state before the lock is released.
auto scope_exit{m_actionCompleteEvent.SetEvent_scope_exit()};
std::unique_lock<std::mutex> lock(m_actionCompleteMutex);
m_stowedErrorInformation = stowedErrorInformation;
m_stowedError = stowedError;
if (m_expectedStatus != WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING)
{
// Note that the order of scope_exit and lock is important - this ensures that scope_exit is
// destroyed *after* lock is destroyed, ensuring that the event is not set to the signalled
// state before the lock is released.
auto scope_exit{m_actionCompleteEvent.SetEvent_scope_exit()};
std::unique_lock<std::mutex> lock(m_actionCompleteMutex);
m_stowedErrorInformation = stowedErrorInformation;
m_stowedError = stowedError;
}
else
{
Log::Write(
Logger::Level::Verbose, "Received error while closing: " + std::to_string(stowedError));
}
}

DWORD WinHttpAction::GetStowedError()
Expand Down Expand Up @@ -564,10 +572,9 @@ namespace Azure { namespace Core { namespace Http { namespace _detail {
{
return;
}

WinHttpAction* httpAction = reinterpret_cast<WinHttpAction*>(dwContext);
try
{
WinHttpAction* httpAction = reinterpret_cast<WinHttpAction*>(dwContext);
httpAction->OnHttpStatusOperation(
hInternet, internetStatus, statusInformation, statusInformationLength);
}
Expand All @@ -578,6 +585,7 @@ namespace Azure { namespace Core { namespace Http { namespace _detail {
Logger::Level::Error,
"Request Failed Exception Thrown: " + std::string(rfe.what()) + rfe.Message);
WinHttpCloseHandle(hInternet);
httpAction->m_httpRequest->MarkRequestHandleClosed();
}
catch (std::exception const& ex)
{
Expand Down
15 changes: 9 additions & 6 deletions sdk/core/azure-core/test/ut/transport_adapter_base_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -383,14 +383,17 @@ namespace Azure { namespace Core { namespace Test {

TEST_P(TransportAdapter, cancelRequest)
{
Azure::Core::Url hostPath(AzureSdkHttpbinServer::Delay() + "/10"); // 10 seconds delay on server
Azure::Core::Context cancelThis = Azure::Core::Context::ApplicationContext.WithDeadline(
std::chrono::system_clock::now() + std::chrono::seconds(3));
Azure::Core::Url hostPath(AzureSdkHttpbinServer::Delay() + "/2"); // 2 seconds delay on server
for (int i = 0; i < 10; i++)
{
Azure::Core::Context cancelThis = Azure::Core::Context::ApplicationContext.WithDeadline(
std::chrono::system_clock::now() + std::chrono::milliseconds(500));

auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, hostPath);
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, hostPath);

// Request will be cancelled 3 seconds after sending the request.
EXPECT_THROW(m_pipeline->Send(request, cancelThis), Azure::Core::OperationCancelledException);
// Request will be canceled 500ms after sending the request.
EXPECT_THROW(m_pipeline->Send(request, cancelThis), Azure::Core::OperationCancelledException);
}
}

TEST_P(TransportAdapter, cancelTransferDownload)
Expand Down