curl transport adapter options (#885)

This commit is contained in:
Victor Vazquez 2020-11-04 18:06:09 -08:00 committed by GitHub
parent b36adc7bd1
commit 7962546009
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 506 additions and 37 deletions

View File

@ -8,11 +8,14 @@ project(${TARGET_NAME} LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CURL_MIN_REQUIRED_VERSION 7.4)
# min version for `CURLSSLOPT_NO_REVOKE`
# https://curl.haxx.se/libcurl/c/CURLOPT_SSL_OPTIONS.html
set(CURL_MIN_REQUIRED_VERSION 7.44)
find_package(CURL ${CURL_MIN_REQUIRED_VERSION} CONFIG)
if(NOT CURL_FOUND)
find_package(CURL ${CURL_MIN_REQUIRED_VERSION} REQUIRED)
endif()
message("Libcurl version ${CURL_VERSION_STRING}")
if(BUILD_TRANSPORT_CURL)
SET(CURL_TRANSPORT_ADAPTER_SRC src/http/curl/curl.cpp)

View File

@ -27,6 +27,84 @@ namespace Azure { namespace Core { namespace Test {
namespace Azure { namespace Core { namespace Http {
/**
* @brief The available options to set libcurl ssl options.
*
* @remark The SDK will map the enum option to libcurl's specific option. See more info here:
* https://curl.haxx.se/libcurl/c/CURLOPT_SSL_OPTIONS.html
*
*/
struct CurlTransportSSLOptions
{
bool AllowBeast = false;
bool NoRevoke = false;
/*
// Requires libcurl version >= 7.68
bool NoPartialchain = false;
// Requires libcurl version >= 7.70
bool RevokeBestEffort = false;
// Requires libcurl version >= 7.71
bool NativeCa = false;
*/
};
/**
* @brief Set the curl connection options like a proxy and CA path.
*
*/
struct CurlTransportOptions
{
/**
* @brief The string for the proxy is passed directly to the libcurl handle without any parsing
*
* @remark No validation for the string is done by the Azure SDK. More about this option:
* https://curl.haxx.se/libcurl/c/CURLOPT_PROXY.html.
*
* @remark The default value is an empty string (no proxy).
*
*/
std::string Proxy;
/**
* @brief The string for the certificate authenticator is sent to libcurl handle directly.
*
* @remark The Azure SDK will not check if the path is valid or not.
*
* @remark The default is the built-in system specific path. More about this option:
* https://curl.haxx.se/libcurl/c/CURLOPT_CAINFO.html
*
*/
std::string CAInfo;
/**
* @brief All HTTP requests will keep the connection channel open to the service.
*
* @remark The channel might be closed by the server if the server response has an error code.
* A connection won't be re-used if it is abandoned in the middle of an operation.
* operation.
*
* @remark This option is managed directly by the Azure SDK. No option is set for the curl
* handle. It is `true` by default.
*/
bool HttpKeepAlive = true;
/**
* @brief This option determines whether curl verifies the authenticity of the peer's
* certificate.
*
* @remark The default value is `true`. More about this option:
* https://curl.haxx.se/libcurl/c/CURLOPT_SSL_VERIFYPEER.html
*
*/
bool SSLVerifyPeer = true;
/**
* @brief Define the SSL options for the libcurl handle.
*
* @remark See more info here: https://curl.haxx.se/libcurl/c/CURLOPT_SSL_OPTIONS.html.
* The default option is all options `false`.
*
*/
CurlTransportSSLOptions SSLOptions;
};
/**
* @brief CURL HTTP connection pool makes it possible to re-use one curl connection to perform
* more than one request. Use this component when connections are not re-used by default.
@ -64,7 +142,9 @@ namespace Azure { namespace Core { namespace Http {
*
* @return #CurlNetworkConnection to use.
*/
static std::unique_ptr<CurlNetworkConnection> GetCurlConnection(Request& request);
static std::unique_ptr<CurlNetworkConnection> GetCurlConnection(
Request& request,
CurlTransportOptions const& options);
/**
* @brief Moves a connection back to the pool to be re-used.

View File

@ -18,13 +18,24 @@
#include "azure/core/http/policy.hpp"
namespace Azure { namespace Core { namespace Http {
/**
* @brief Concrete implementation of an HTTP Transport that uses libcurl.
*
*/
class CurlTransport : public HttpTransport {
private:
CurlTransportOptions m_options;
public:
/**
* @brief Construct a new Curl Transport object.
*
* @param options Optional parameter to override the default options.
*/
CurlTransport(CurlTransportOptions const& options = CurlTransportOptions()) : m_options(options)
{
}
/**
* @brief Implements interface to send an HTTP Request and produce an HTTP RawResponse
*

View File

@ -319,14 +319,25 @@ namespace Azure { namespace Core { namespace Http {
return eof && m_sessionState != SessionState::PERFORM;
}
/**
* @brief All connections will request to keep the channel open to re-use the
* connection.
*
* @remark This option can be disabled from the transport adapter options. When disabled, the
* session won't return connections to the connection pool. Connection will be closed as soon as
* the request is completed.
*
*/
bool m_keepAlive = true;
public:
/**
* @brief Construct a new Curl Session object. Init internal libcurl handler.
*
* @param request reference to an HTTP Request.
*/
CurlSession(Request& request, std::unique_ptr<CurlNetworkConnection> connection)
: m_connection(std::move(connection)), m_request(request)
CurlSession(Request& request, std::unique_ptr<CurlNetworkConnection> connection, bool keepAlive)
: m_connection(std::move(connection)), m_request(request), m_keepAlive(keepAlive)
{
m_bodyStartInBuffer = -1;
m_innerBufferSize = Details::c_DefaultLibcurlReaderSize;
@ -342,7 +353,7 @@ namespace Azure { namespace Core { namespace Http {
// By not moving the connection back to the pool, it gets destroyed calling the connection
// destructor to clean libcurl handle and close the connection.
// IsEOF will also handle a connection that fail to complete an upload request.
if (IsEOF())
if (IsEOF() && m_keepAlive)
{
CurlConnectionPool::MoveConnectionBackToPool(std::move(m_connection), m_lastStatusCode);
}

View File

@ -13,6 +13,7 @@
#endif
#include <algorithm>
#include <curl/curl.h>
#include <string>
#include <thread>
@ -145,6 +146,7 @@ using Azure::Core::Http::CurlConnectionPool;
using Azure::Core::Http::CurlNetworkConnection;
using Azure::Core::Http::CurlSession;
using Azure::Core::Http::CurlTransport;
using Azure::Core::Http::CurlTransportOptions;
using Azure::Core::Http::HttpStatusCode;
using Azure::Core::Http::LogClassification;
using Azure::Core::Http::RawResponse;
@ -155,8 +157,8 @@ std::unique_ptr<RawResponse> CurlTransport::Send(Context const& context, Request
{
// Create CurlSession to perform request
LogThis("Creating a new session.");
auto session
= std::make_unique<CurlSession>(request, CurlConnectionPool::GetCurlConnection(request));
auto session = std::make_unique<CurlSession>(
request, CurlConnectionPool::GetCurlConnection(request, m_options), m_options.HttpKeepAlive);
CURLcode performing;
// Try to send the request. If we get CURLE_UNSUPPORTED_PROTOCOL back, it means the connection is
@ -173,8 +175,10 @@ std::unique_ptr<RawResponse> CurlTransport::Send(Context const& context, Request
break;
}
// Let session be destroyed and create a new one to get a new connection
session
= std::make_unique<CurlSession>(request, CurlConnectionPool::GetCurlConnection(request));
session = std::make_unique<CurlSession>(
request,
CurlConnectionPool::GetCurlConnection(request, m_options),
m_options.HttpKeepAlive);
}
if (performing != CURLE_OK)
@ -1012,7 +1016,9 @@ std::map<std::string, std::list<std::unique_ptr<CurlNetworkConnection>>>
int32_t CurlConnectionPool::s_connectionCounter = 0;
bool CurlConnectionPool::s_isCleanConnectionsRunning = false;
std::unique_ptr<CurlNetworkConnection> CurlConnectionPool::GetCurlConnection(Request& request)
std::unique_ptr<CurlNetworkConnection> CurlConnectionPool::GetCurlConnection(
Request& request,
CurlTransportOptions const& options)
{
std::string const& host = request.GetUrl().GetHost();
@ -1073,6 +1079,73 @@ std::unique_ptr<CurlNetworkConnection> CurlConnectionPool::GetCurlConnection(Req
60L * 60L * 24L,
Details::c_DefaultFailedToGetNewConnectionTemplate + host);
/******************** Curl handle options apply to all connections created
* The keepAlive option is managed by the session directly.
*/
if (!options.Proxy.empty())
{
SetLibcurlOption(
newHandle,
CURLOPT_PROXY,
options.Proxy.c_str(),
Details::c_DefaultFailedToGetNewConnectionTemplate + host
+ ". Failed to set proxy to:" + options.Proxy);
}
if (!options.CAInfo.empty())
{
SetLibcurlOption(
newHandle,
CURLOPT_CAINFO,
options.CAInfo.c_str(),
Details::c_DefaultFailedToGetNewConnectionTemplate + host
+ ". Failed to set CA cert to:" + options.CAInfo);
}
long sslOption = 0;
if (options.SSLOptions.AllowBeast)
{
sslOption |= CURLSSLOPT_ALLOW_BEAST;
}
if (options.SSLOptions.NoRevoke)
{
sslOption |= CURLSSLOPT_NO_REVOKE;
}
/*
// Requires libcurl version >= 7.68
if (options.SSLOptions.NoPartialchain)
{
sslOption |= CURLSSLOPT_NO_PARTIALCHAIN;
}
// Requires libcurl version >= 7.70
if (options.SSLOptions.RevokeBestEffort)
{
sslOption |= CURLSSLOPT_REVOKE_BEST_EFFORT;
}
// Requires libcurl version >= 7.71
if (options.SSLOptions.NativeCa)
{
sslOption |= CURLSSLOPT_NATIVE_CA;
}
*/
SetLibcurlOption(
newHandle,
CURLOPT_SSL_OPTIONS,
sslOption,
Details::c_DefaultFailedToGetNewConnectionTemplate + host
+ ". Failed to set ssl options to long bitmask:" + std::to_string(sslOption));
if (!options.SSLVerifyPeer)
{
SetLibcurlOption(
newHandle,
CURLOPT_SSL_VERIFYPEER,
0L,
Details::c_DefaultFailedToGetNewConnectionTemplate + host
+ ". Failed to disable ssl verify peer.");
}
auto performResult = curl_easy_perform(newHandle);
if (performResult != CURLE_OK)
{

View File

@ -19,10 +19,15 @@ project (${TARGET_NAME} LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED True)
if(BUILD_TRANSPORT_CURL)
SET(CURL_OPTIONS_TESTS curl_options.cpp)
endif()
include(GoogleTest)
add_executable (
${TARGET_NAME}
context.cpp
${CURL_OPTIONS_TESTS}
curl_session_test.cpp
datetime.cpp
http.cpp

View File

@ -0,0 +1,286 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#include "gtest/gtest.h"
#include <azure/core/context.hpp>
#include <azure/core/http/curl/curl.hpp>
#include <azure/core/http/http.hpp>
#include <azure/core/http/pipeline.hpp>
#include <azure/core/http/policy.hpp>
#include <azure/core/response.hpp>
#include <string>
#include <vector>
namespace Azure { namespace Core { namespace Test {
// proxy server can take some minutes to handle the request. Only testing HTTP proxy
// Test is disabled until there is a reliable proxy to be used for CI111
TEST(CurlTransportOptions, DISABLED_proxy)
{
Azure::Core::Http::CurlTransportOptions curlOptions;
// This proxy is currently alive but eventually we might want our own proxy server to be
// available.
curlOptions.Proxy = "136.228.165.138:8080";
auto transportAdapter = std::make_shared<Azure::Core::Http::CurlTransport>(curlOptions);
auto transportPolicy = std::make_unique<Azure::Core::Http::TransportPolicy>(transportAdapter);
std::vector<std::unique_ptr<Azure::Core::Http::HttpPolicy>> policies;
policies.emplace_back(std::move(transportPolicy));
Azure::Core::Http::HttpPipeline pipeline(policies);
Azure::Core::Http::Url url("http://httpbin.org/get");
Azure::Core::Http::Request request(Azure::Core::Http::HttpMethod::Get, url);
std::unique_ptr<Azure::Core::Http::RawResponse> response;
EXPECT_NO_THROW(response = pipeline.Send(Azure::Core::GetApplicationContext(), request));
auto responseCode = response->GetStatusCode();
int expectedCode = 200;
EXPECT_PRED2(
[](int expected, int code) { return expected == code; },
expectedCode,
static_cast<typename std::underlying_type<Azure::Core::Http::HttpStatusCode>::type>(
responseCode));
}
/******************************* SSL options. ************************/
TEST(CurlTransportOptions, noRevoke)
{
Azure::Core::Http::CurlTransportOptions curlOptions;
curlOptions.SSLOptions.NoRevoke = true;
auto transportAdapter = std::make_shared<Azure::Core::Http::CurlTransport>(curlOptions);
auto transportPolicy = std::make_unique<Azure::Core::Http::TransportPolicy>(transportAdapter);
std::vector<std::unique_ptr<Azure::Core::Http::HttpPolicy>> policies;
policies.emplace_back(std::move(transportPolicy));
Azure::Core::Http::HttpPipeline pipeline(policies);
Azure::Core::Http::Url url("https://httpbin.org/get");
Azure::Core::Http::Request request(Azure::Core::Http::HttpMethod::Get, url);
std::unique_ptr<Azure::Core::Http::RawResponse> response;
EXPECT_NO_THROW(response = pipeline.Send(Azure::Core::GetApplicationContext(), request));
auto responseCode = response->GetStatusCode();
int expectedCode = 200;
EXPECT_PRED2(
[](int expected, int code) { return expected == code; },
expectedCode,
static_cast<typename std::underlying_type<Azure::Core::Http::HttpStatusCode>::type>(
responseCode));
// Clean the connection from the pool *Windows fails to clean if we leave to be clean uppon
// app-destruction
EXPECT_NO_THROW(Azure::Core::Http::CurlConnectionPool::ConnectionPoolIndex.clear());
}
TEST(CurlTransportOptions, allowBeast)
{
Azure::Core::Http::CurlTransportOptions curlOptions;
curlOptions.SSLOptions.AllowBeast = true;
auto transportAdapter = std::make_shared<Azure::Core::Http::CurlTransport>(curlOptions);
auto transportPolicy = std::make_unique<Azure::Core::Http::TransportPolicy>(transportAdapter);
std::vector<std::unique_ptr<Azure::Core::Http::HttpPolicy>> policies;
policies.emplace_back(std::move(transportPolicy));
Azure::Core::Http::HttpPipeline pipeline(policies);
Azure::Core::Http::Url url("https://httpbin.org/get");
Azure::Core::Http::Request request(Azure::Core::Http::HttpMethod::Get, url);
std::unique_ptr<Azure::Core::Http::RawResponse> response;
EXPECT_NO_THROW(response = pipeline.Send(Azure::Core::GetApplicationContext(), request));
auto responseCode = response->GetStatusCode();
int expectedCode = 200;
EXPECT_PRED2(
[](int expected, int code) { return expected == code; },
expectedCode,
static_cast<typename std::underlying_type<Azure::Core::Http::HttpStatusCode>::type>(
responseCode));
// Clean the connection from the pool *Windows fails to clean if we leave to be clean uppon
// app-destruction
EXPECT_NO_THROW(Azure::Core::Http::CurlConnectionPool::ConnectionPoolIndex.clear());
}
/*
// Requires libcurl version >= 7.68
TEST(CurlTransportOptions, nativeCA)
{
Azure::Core::Http::CurlTransportOptions curlOptions;
curlOptions.SSLOptions.NativeCa = true;
auto transportAdapter = std::make_shared<Azure::Core::Http::CurlTransport>(curlOptions);
auto transportPolicy = std::make_unique<Azure::Core::Http::TransportPolicy>(transportAdapter);
std::vector<std::unique_ptr<Azure::Core::Http::HttpPolicy>> policies;
policies.emplace_back(std::move(transportPolicy));
Azure::Core::Http::HttpPipeline pipeline(policies);
Azure::Core::Http::Url url("https://httpbin.org/get");
Azure::Core::Http::Request request(Azure::Core::Http::HttpMethod::Get, url);
std::unique_ptr<Azure::Core::Http::RawResponse> response;
EXPECT_NO_THROW(response = pipeline.Send(Azure::Core::GetApplicationContext(), request));
auto responseCode = response->GetStatusCode();
int expectedCode = 200;
EXPECT_PRED2(
[](int expected, int code) { return expected == code; },
expectedCode,
static_cast<typename std::underlying_type<Azure::Core::Http::HttpStatusCode>::type>(
responseCode));
}
// Requires libcurl version >= 7.70
TEST(CurlTransportOptions, noPartialChain)
{
Azure::Core::Http::CurlTransportOptions curlOptions;
curlOptions.SSLOptions.NoPartialchain = true;
auto transportAdapter = std::make_shared<Azure::Core::Http::CurlTransport>(curlOptions);
auto transportPolicy = std::make_unique<Azure::Core::Http::TransportPolicy>(transportAdapter);
std::vector<std::unique_ptr<Azure::Core::Http::HttpPolicy>> policies;
policies.emplace_back(std::move(transportPolicy));
Azure::Core::Http::HttpPipeline pipeline(policies);
Azure::Core::Http::Url url("https://httpbin.org/get");
Azure::Core::Http::Request request(Azure::Core::Http::HttpMethod::Get, url);
std::unique_ptr<Azure::Core::Http::RawResponse> response;
EXPECT_NO_THROW(response = pipeline.Send(Azure::Core::GetApplicationContext(), request));
auto responseCode = response->GetStatusCode();
int expectedCode = 200;
EXPECT_PRED2(
[](int expected, int code) { return expected == code; },
expectedCode,
static_cast<typename std::underlying_type<Azure::Core::Http::HttpStatusCode>::type>(
responseCode));
}
// Requires libcurl version >= 7.71
TEST(CurlTransportOptions, bestEffort)
{
Azure::Core::Http::CurlTransportOptions curlOptions;
curlOptions.SSLOptions.RevokeBestEffort = true;
auto transportAdapter = std::make_shared<Azure::Core::Http::CurlTransport>(curlOptions);
auto transportPolicy = std::make_unique<Azure::Core::Http::TransportPolicy>(transportAdapter);
std::vector<std::unique_ptr<Azure::Core::Http::HttpPolicy>> policies;
policies.emplace_back(std::move(transportPolicy));
Azure::Core::Http::HttpPipeline pipeline(policies);
Azure::Core::Http::Url url("https://httpbin.org/get");
Azure::Core::Http::Request request(Azure::Core::Http::HttpMethod::Get, url);
std::unique_ptr<Azure::Core::Http::RawResponse> response;
EXPECT_NO_THROW(response = pipeline.Send(Azure::Core::GetApplicationContext(), request));
auto responseCode = response->GetStatusCode();
int expectedCode = 200;
EXPECT_PRED2(
[](int expected, int code) { return expected == code; },
expectedCode,
static_cast<typename std::underlying_type<Azure::Core::Http::HttpStatusCode>::type>(
responseCode));
}
*/
TEST(CurlTransportOptions, sslVerifyOff)
{
Azure::Core::Http::CurlTransportOptions curlOptions;
// If ssl verify is not disabled, this test would fail because the caInfo is not OK
curlOptions.SSLVerifyPeer = false;
// This ca info should be ignored by verify disable and test should work
curlOptions.CAInfo = "/";
auto transportAdapter = std::make_shared<Azure::Core::Http::CurlTransport>(curlOptions);
auto transportPolicy = std::make_unique<Azure::Core::Http::TransportPolicy>(transportAdapter);
std::vector<std::unique_ptr<Azure::Core::Http::HttpPolicy>> policies;
policies.emplace_back(std::move(transportPolicy));
Azure::Core::Http::HttpPipeline pipeline(policies);
// Use https
Azure::Core::Http::Url url("https://httpbin.org/get");
Azure::Core::Http::Request request(Azure::Core::Http::HttpMethod::Get, url);
std::unique_ptr<Azure::Core::Http::RawResponse> response;
EXPECT_NO_THROW(response = pipeline.Send(Azure::Core::GetApplicationContext(), request));
auto responseCode = response->GetStatusCode();
int expectedCode = 200;
EXPECT_PRED2(
[](int expected, int code) { return expected == code; },
expectedCode,
static_cast<typename std::underlying_type<Azure::Core::Http::HttpStatusCode>::type>(
responseCode));
// Clean the connection from the pool *Windows fails to clean if we leave to be clean uppon
// app-destruction
EXPECT_NO_THROW(Azure::Core::Http::CurlConnectionPool::ConnectionPoolIndex.clear());
}
TEST(CurlTransportOptions, httpsDefault)
{
auto transportAdapter = std::make_shared<Azure::Core::Http::CurlTransport>();
auto transportPolicy = std::make_unique<Azure::Core::Http::TransportPolicy>(transportAdapter);
std::vector<std::unique_ptr<Azure::Core::Http::HttpPolicy>> policies;
policies.emplace_back(std::move(transportPolicy));
Azure::Core::Http::HttpPipeline pipeline(policies);
// Use https
Azure::Core::Http::Url url("https://httpbin.org/get");
Azure::Core::Http::Request request(Azure::Core::Http::HttpMethod::Get, url);
std::unique_ptr<Azure::Core::Http::RawResponse> response;
EXPECT_NO_THROW(response = pipeline.Send(Azure::Core::GetApplicationContext(), request));
auto responseCode = response->GetStatusCode();
int expectedCode = 200;
EXPECT_PRED2(
[](int expected, int code) { return expected == code; },
expectedCode,
static_cast<typename std::underlying_type<Azure::Core::Http::HttpStatusCode>::type>(
responseCode));
// Clean the connection from the pool *Windows fails to clean if we leave to be clean uppon
// app-destruction
EXPECT_NO_THROW(Azure::Core::Http::CurlConnectionPool::ConnectionPoolIndex.clear());
}
TEST(CurlTransportOptions, disableKeepAlive)
{
Azure::Core::Http::CurlTransportOptions curlOptions;
curlOptions.HttpKeepAlive = false;
auto transportAdapter = std::make_shared<Azure::Core::Http::CurlTransport>(curlOptions);
auto transportPolicy = std::make_unique<Azure::Core::Http::TransportPolicy>(transportAdapter);
{
// use inner scope to remove the pipeline and make sure we don't keep the connection in the
// pool
std::vector<std::unique_ptr<Azure::Core::Http::HttpPolicy>> policies;
policies.emplace_back(std::move(transportPolicy));
Azure::Core::Http::HttpPipeline pipeline(policies);
Azure::Core::Http::Url url("http://httpbin.org/get");
Azure::Core::Http::Request request(Azure::Core::Http::HttpMethod::Get, url);
std::unique_ptr<Azure::Core::Http::RawResponse> response;
EXPECT_NO_THROW(response = pipeline.Send(Azure::Core::GetApplicationContext(), request));
auto responseCode = response->GetStatusCode();
int expectedCode = 200;
EXPECT_PRED2(
[](int expected, int code) { return expected == code; },
expectedCode,
static_cast<typename std::underlying_type<Azure::Core::Http::HttpStatusCode>::type>(
responseCode));
}
// Make sure there are no connections in the pool
EXPECT_EQ(Azure::Core::Http::CurlConnectionPool::ConnectionPoolIndex.size(), 0);
}
}}} // namespace Azure::Core::Test

View File

@ -37,8 +37,8 @@ namespace Azure { namespace Core { namespace Test {
// Move the curlMock to build a session and then send the request
// The session will get the response we mock before, so it will pass for this GET
auto session
= std::make_unique<Azure::Core::Http::CurlSession>(request, std::move(uniqueCurlMock));
auto session = std::make_unique<Azure::Core::Http::CurlSession>(
request, std::move(uniqueCurlMock), true);
EXPECT_NO_THROW(session->Perform(Azure::Core::GetApplicationContext()));
}
@ -70,8 +70,8 @@ namespace Azure { namespace Core { namespace Test {
{
// Create the session inside scope so it is released and the connection is moved to the pool
auto session
= std::make_unique<Azure::Core::Http::CurlSession>(request, std::move(uniqueCurlMock));
auto session = std::make_unique<Azure::Core::Http::CurlSession>(
request, std::move(uniqueCurlMock), true);
EXPECT_NO_THROW(session->Perform(Azure::Core::GetApplicationContext()));
}

View File

@ -480,31 +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
TEST_F(TransportAdapter, requestFailedException)
{
auto result = pipeline.Send(context, request);
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);
}
catch (Azure::Core::RequestFailedException& err)
TEST_F(TransportAdapter, dynamicCast)
{
// if ref can't be cast, it throws
EXPECT_NO_THROW(dynamic_cast<Azure::Core::Http::TransportException&>(err));
EXPECT_NO_THROW(dynamic_cast<std::runtime_error&>(err));
EXPECT_THROW(dynamic_cast<std::range_error&>(err), std::bad_cast);
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<Azure::Core::Http::TransportException&>(err));
EXPECT_NO_THROW(dynamic_cast<std::runtime_error&>(err));
EXPECT_THROW(dynamic_cast<std::range_error&>(err), std::bad_cast);
}
}
}
}}} // namespace Azure::Core::Test