diff --git a/sdk/core/azure-core/CHANGELOG.md b/sdk/core/azure-core/CHANGELOG.md index 5dd93f6d9..a1a162eec 100644 --- a/sdk/core/azure-core/CHANGELOG.md +++ b/sdk/core/azure-core/CHANGELOG.md @@ -18,6 +18,14 @@ - Prevent pipeline of length zero to be created. +### New Features + +- Add `RequestFailException` deriving from `std::runtime_error`. + +### Other changes and Improvements + +- Updated `TransportException` and `InvalidHeaderException` to derive from `RequestFailedException`. + ## 1.0.0-beta.2 (2020-10-09) ### Breaking Changes diff --git a/sdk/core/azure-core/inc/azure/core/exception.hpp b/sdk/core/azure-core/inc/azure/core/exception.hpp new file mode 100644 index 000000000..ee05552f7 --- /dev/null +++ b/sdk/core/azure-core/inc/azure/core/exception.hpp @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// SPDX-License-Identifier: MIT + +/** + * @file + * @brief Define RequestFailedException. It is used by HTTP exceptions. + */ + +#pragma once + +#include + +namespace Azure { namespace Core { + /** + * @brief An error while trying to send a request to Azure service. + * + */ + struct RequestFailedException : public std::runtime_error + { + /** + * @brief Construct a new Request Failed Exception object. + * + * @param message The error description. + */ + explicit RequestFailedException(std::string const& message) : std::runtime_error(message) {} + }; +}} // namespace Azure::Core diff --git a/sdk/core/azure-core/inc/azure/core/http/http.hpp b/sdk/core/azure-core/inc/azure/core/http/http.hpp index ce279c563..2a60ac453 100644 --- a/sdk/core/azure-core/inc/azure/core/http/http.hpp +++ b/sdk/core/azure-core/inc/azure/core/http/http.hpp @@ -8,6 +8,7 @@ #pragma once +#include "azure/core/exception.hpp" #include "azure/core/http/body_stream.hpp" #include "azure/core/internal/contract.hpp" @@ -47,6 +48,43 @@ namespace Azure { namespace Core { namespace Http { std::string const& headerValue); } // namespace Details + /********************* Exceptions **********************/ + /** + * @brief HTTP transport layer error. + */ + struct TransportException : public Azure::Core::RequestFailedException + { + /** + * @brief An error while sending the HTTP request with the transport adapter. + * + * @remark The transport policy will throw this error whenever the transport adapter fail to + * perform a request. + * + * @param message The error description. + */ + explicit TransportException(std::string const& message) + : Azure::Core::RequestFailedException(message) + { + } + }; + + /** + * @brief An invalid header key name in @Request or @RawResponse. + * + */ + struct InvalidHeaderException : public Azure::Core::RequestFailedException + { + /** + * @brief An invalid header key name detected in the HTTP request or response. + * + * @param message The error description. + */ + explicit InvalidHeaderException(std::string const& message) + : Azure::Core::RequestFailedException(message) + { + } + }; + /** * @brief HTTP transport implementation used. */ @@ -437,10 +475,10 @@ namespace Azure { namespace Core { namespace Http { */ explicit Request(HttpMethod httpMethod, Url url, bool downloadViaStream) : Request( - httpMethod, - std::move(url), - NullBodyStream::GetNullBodyStream(), - downloadViaStream) + httpMethod, + std::move(url), + NullBodyStream::GetNullBodyStream(), + downloadViaStream) { } @@ -524,35 +562,6 @@ namespace Azure { namespace Core { namespace Http { void StartTry(); }; - /* - * RawResponse exceptions - */ - /** - * @brief Couldn't resolve HTTP host. - */ - struct CouldNotResolveHostException : public std::runtime_error - { - explicit CouldNotResolveHostException(std::string const& msg) : std::runtime_error(msg) {} - }; - - // Any other exception from transport layer without a specific exception defined above - /** - * @brief HTTP transport layer error. - */ - struct TransportException : public std::runtime_error - { - explicit TransportException(std::string const& msg) : std::runtime_error(msg) {} - }; - - /** - * @brief An invalid header key name in @Request or @RawResponse - * - */ - struct InvalidHeaderException : public std::runtime_error - { - explicit InvalidHeaderException(std::string const& msg) : std::runtime_error(msg) {} - }; - /** * @brief Raw HTTP response. */ diff --git a/sdk/core/azure-core/src/http/curl/curl.cpp b/sdk/core/azure-core/src/http/curl/curl.cpp index 48522c799..7f229acc8 100644 --- a/sdk/core/azure-core/src/http/curl/curl.cpp +++ b/sdk/core/azure-core/src/http/curl/curl.cpp @@ -176,18 +176,8 @@ std::unique_ptr CurlTransport::Send(Context const& context, Request if (performing != CURLE_OK) { - switch (performing) - { - case CURLE_COULDNT_RESOLVE_HOST: - { - throw CouldNotResolveHostException("Could not resolve host " + request.GetUrl().GetHost()); - } - default: - { - throw TransportException( - "Error while sending request. " + std::string(curl_easy_strerror(performing))); - } - } + throw Azure::Core::Http::TransportException( + "Error while sending request. " + std::string(curl_easy_strerror(performing))); } LogThis("Request completed. Moving response out of session and session to response."); diff --git a/sdk/core/azure-core/src/http/retry_policy.cpp b/sdk/core/azure-core/src/http/retry_policy.cpp index e108d87a4..84c1e8b3d 100644 --- a/sdk/core/azure-core/src/http/retry_policy.cpp +++ b/sdk/core/azure-core/src/http/retry_policy.cpp @@ -150,13 +150,6 @@ std::unique_ptr Azure::Core::Http::RetryPolicy::Send( return response; } } - catch (CouldNotResolveHostException const&) - { - if (!ShouldRetryOnTransportFailure(m_retryOptions, attempt, retryAfter)) - { - throw; - } - } catch (TransportException const&) { if (!ShouldRetryOnTransportFailure(m_retryOptions, attempt, retryAfter)) diff --git a/sdk/core/azure-core/test/e2e/azure_core_with_curl_bodyBuffer.cpp b/sdk/core/azure-core/test/e2e/azure_core_with_curl_bodyBuffer.cpp index bcf628deb..de2970072 100644 --- a/sdk/core/azure-core/test/e2e/azure_core_with_curl_bodyBuffer.cpp +++ b/sdk/core/azure-core/test/e2e/azure_core_with_curl_bodyBuffer.cpp @@ -62,11 +62,7 @@ int main() doDeleteRequest(context, httpPipeline); doPatchRequest(context, httpPipeline); } - catch (Http::CouldNotResolveHostException const& e) - { - cout << e.what() << endl; - } - catch (Http::TransportException const& e) + catch (Azure::Core::RequestFailedException const& e) { cout << e.what() << endl; } diff --git a/sdk/core/azure-core/test/e2e/azure_core_with_curl_bodyStream.cpp b/sdk/core/azure-core/test/e2e/azure_core_with_curl_bodyStream.cpp index e329c59c6..7020ee46d 100644 --- a/sdk/core/azure-core/test/e2e/azure_core_with_curl_bodyStream.cpp +++ b/sdk/core/azure-core/test/e2e/azure_core_with_curl_bodyStream.cpp @@ -7,9 +7,9 @@ * */ -#include #include #include +#include #include #include @@ -61,11 +61,7 @@ int main() doNoPathGetRequest(context, httpPipeline); doPutRequest(context, httpPipeline); } - catch (Http::CouldNotResolveHostException const& e) - { - cout << e.what() << endl; - } - catch (Http::TransportException const& e) + catch (Azure::Core::RequestFailedException const& e) { cout << e.what() << endl; } @@ -172,7 +168,7 @@ void printStream(Context const& context, std::unique_ptr resp } cout << static_cast::type>( - response->GetStatusCode()) + response->GetStatusCode()) << endl; cout << response->GetReasonPhrase() << endl; cout << "headers:" << endl; diff --git a/sdk/core/azure-core/test/ut/transport_adapter.cpp b/sdk/core/azure-core/test/ut/transport_adapter.cpp index 14bc68486..47c141435 100644 --- a/sdk/core/azure-core/test/ut/transport_adapter.cpp +++ b/sdk/core/azure-core/test/ut/transport_adapter.cpp @@ -480,4 +480,31 @@ namespace Azure { namespace Core { namespace Test { t1.join(); } + TEST_F(TransportAdapter, requestFailedException) + { + Azure::Core::Http::Url host("http://unresolvedHost.org/get"); + + auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host); + EXPECT_THROW(pipeline.Send(context, request), Azure::Core::RequestFailedException); + } + + TEST_F(TransportAdapter, dynamicCast) + { + Azure::Core::Http::Url host("http://unresolvedHost.org/get"); + auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host); + + // test dynamic cast + try + { + auto result = pipeline.Send(context, request); + } + catch (Azure::Core::RequestFailedException& err) + { + // if ref can't be cast, it throws + EXPECT_NO_THROW(dynamic_cast(err)); + EXPECT_NO_THROW(dynamic_cast(err)); + EXPECT_THROW(dynamic_cast(err), std::bad_cast); + } + } + }}} // namespace Azure::Core::Test diff --git a/sdk/storage/azure-storage-common/src/storage_retry_policy.cpp b/sdk/storage/azure-storage-common/src/storage_retry_policy.cpp index c4c90fc68..24c4ee6db 100644 --- a/sdk/storage/azure-storage-common/src/storage_retry_policy.cpp +++ b/sdk/storage/azure-storage-common/src/storage_retry_policy.cpp @@ -77,14 +77,7 @@ namespace Azure { namespace Storage { break; } } - catch (Azure::Core::Http::CouldNotResolveHostException const&) - { - if (lastAttempt) - { - throw; - } - } - catch (Azure::Core::Http::TransportException const&) + catch (Azure::Core::RequestFailedException const&) { if (lastAttempt) {