curl transport adapter options (#885)
This commit is contained in:
parent
b36adc7bd1
commit
7962546009
@ -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)
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
*
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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
|
||||
|
||||
286
sdk/core/azure-core/test/ut/curl_options.cpp
Normal file
286
sdk/core/azure-core/test/ut/curl_options.cpp
Normal 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
|
||||
@ -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()));
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user