Skip to content

Commit c060727

Browse files
author
Hannes Rantzsch
committed
alternative asio client based on botan (WIP)
1 parent 3d823f5 commit c060727

File tree

4 files changed

+64
-20
lines changed

4 files changed

+64
-20
lines changed

Release/include/cpprest/http_client.h

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ typedef void* native_handle;
6161
#include "cpprest/oauth2.h"
6262

6363
#if !defined(_WIN32) && !defined(__cplusplus_winrt) || defined(CPPREST_FORCE_HTTP_CLIENT_ASIO)
64+
65+
#if defined(CPPREST_BOTAN_SSL)
66+
#include <botan/asio_context.h>
67+
#else // CPPREST_BOTAN_SSL
68+
6469
#if defined(__clang__)
6570
#pragma clang diagnostic push
6671
#pragma clang diagnostic ignored "-Wconversion"
@@ -69,6 +74,9 @@ typedef void* native_handle;
6974
#if defined(__clang__)
7075
#pragma clang diagnostic pop
7176
#endif
77+
78+
#endif // CPPREST_BOTAN_SSL
79+
7280
#endif
7381

7482
/// The web namespace contains functionality common to multiple protocols like HTTP and WebSockets.
@@ -86,6 +94,12 @@ namespace client
8694
using web::credentials;
8795
using web::web_proxy;
8896

97+
#if defined(CPPREST_BOTAN_SSL)
98+
using ssl_context_t = Botan::TLS::Context;
99+
#else
100+
using ssl_context_t = boost::asio::ssl::context;
101+
#endif
102+
89103
/// <summary>
90104
/// HTTP client configuration class, used to set the possible configuration options
91105
/// used to create an http_client instance.
@@ -334,15 +348,15 @@ class http_client_config
334348
/// </summary>
335349
/// <param name="callback">A user callback allowing for customization of the ssl context at construction
336350
/// time.</param>
337-
void set_ssl_context_callback(const std::function<void(boost::asio::ssl::context&)>& callback)
351+
void set_ssl_context_callback(const std::function<void(ssl_context_t&)>& callback)
338352
{
339353
m_ssl_context_callback = callback;
340354
}
341355

342356
/// <summary>
343357
/// Gets the user's callback to allow for customization of the ssl context.
344358
/// </summary>
345-
const std::function<void(boost::asio::ssl::context&)>& get_ssl_context_callback() const
359+
const std::function<void(ssl_context_t&)>& get_ssl_context_callback() const
346360
{
347361
return m_ssl_context_callback;
348362
}
@@ -386,7 +400,7 @@ class http_client_config
386400
std::function<void(native_handle)> m_set_user_nativesessionhandle_options;
387401

388402
#if !defined(_WIN32) && !defined(__cplusplus_winrt) || defined(CPPREST_FORCE_HTTP_CLIENT_ASIO)
389-
std::function<void(boost::asio::ssl::context&)> m_ssl_context_callback;
403+
std::function<void(ssl_context_t&)> m_ssl_context_callback;
390404
bool m_tlsext_sni_enabled;
391405
#endif
392406
#if defined(_WIN32) && !defined(__cplusplus_winrt)
@@ -402,6 +416,8 @@ class http_pipeline;
402416
class http_client
403417
{
404418
public:
419+
using ssl_context = ssl_context_t;
420+
405421
/// <summary>
406422
/// Creates a new http_client connected to specified uri.
407423
/// </summary>

Release/src/http/client/http_client_asio.cpp

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,19 @@
2525
#pragma clang diagnostic ignored "-Wunused-local-typedef"
2626
#pragma clang diagnostic ignored "-Winfinite-recursion"
2727
#endif
28+
2829
#include <boost/algorithm/string.hpp>
30+
#include <boost/asio/steady_timer.hpp>
31+
#include <boost/bind.hpp>
32+
33+
#if defined(CPPREST_BOTAN_SSL)
34+
#include <botan/asio_stream.h>
35+
#else
2936
#include <boost/asio.hpp>
3037
#include <boost/asio/ssl.hpp>
3138
#include <boost/asio/ssl/error.hpp>
32-
#include <boost/asio/steady_timer.hpp>
33-
#include <boost/bind.hpp>
39+
#endif
40+
3441
#if defined(__clang__)
3542
#pragma clang diagnostic pop
3643
#endif
@@ -87,8 +94,7 @@ namespace
8794
{
8895
const std::string CRLF("\r\n");
8996

90-
std::string calc_cn_host(const web::http::uri& baseUri,
91-
const web::http::http_headers& requestHeaders)
97+
std::string calc_cn_host(const web::http::uri& baseUri, const web::http::http_headers& requestHeaders)
9298
{
9399
std::string result;
94100
if (baseUri.scheme() == U("https"))
@@ -142,9 +148,18 @@ static std::string generate_base64_userpass(const ::web::credentials& creds)
142148

143149
class asio_connection_pool;
144150

151+
#if defined(CPPREST_BOTAN_SSL)
152+
using ssl_stream_t = Botan::TLS::Stream<tcp::socket&, Botan::TLS::Client>;
153+
using ssl_handshake_type_t = Botan::TLS::handshake_type;
154+
#else
155+
using ssl_stream_t = boost::asio::ssl::stream<tcp::socket&>;
156+
using ssl_handshake_type_t = boost::asio::ssl::stream_base::handshake_type;
157+
#endif
158+
145159
class asio_connection
146160
{
147161
friend class asio_client;
162+
using ssl_context_t = http_client::ssl_context;
148163

149164
public:
150165
asio_connection(boost::asio::io_service& io_service)
@@ -161,20 +176,24 @@ class asio_connection
161176
~asio_connection() { close(); }
162177

163178
// This simply instantiates the internal state to support ssl. It does not perform the handshake.
164-
void upgrade_to_ssl(std::string&& cn_hostname,
165-
const std::function<void(boost::asio::ssl::context&)>& ssl_context_callback)
179+
void upgrade_to_ssl(std::string&& cn_hostname, const std::function<void(ssl_context_t&)>& ssl_context_callback)
166180
{
167181
std::lock_guard<std::mutex> lock(m_socket_lock);
168182
assert(!is_ssl());
183+
#if defined(CPPREST_BOTAN_SSL)
184+
Botan::TLS::Context ssl_context;
185+
ssl_context_callback(ssl_context);
186+
ssl_context.serverInfo = Botan::TLS::Server_Information(m_cn_hostname);
187+
#else
169188
boost::asio::ssl::context ssl_context(boost::asio::ssl::context::sslv23);
170189
ssl_context.set_default_verify_paths();
171190
ssl_context.set_options(boost::asio::ssl::context::default_workarounds);
172191
if (ssl_context_callback)
173192
{
174193
ssl_context_callback(ssl_context);
175194
}
176-
m_ssl_stream = utility::details::make_unique<boost::asio::ssl::stream<boost::asio::ip::tcp::socket&>>(
177-
m_socket, ssl_context);
195+
#endif
196+
m_ssl_stream = utility::details::make_unique<ssl_stream_t>(m_socket, ssl_context);
178197
m_cn_hostname = std::move(cn_hostname);
179198
}
180199

@@ -232,6 +251,7 @@ class asio_connection
232251
// server due to inactivity. Unfortunately, the exact error we get
233252
// in this case depends on the Boost.Asio version used.
234253
#if BOOST_ASIO_VERSION >= 101008
254+
// TODO
235255
if (boost::asio::ssl::error::stream_truncated == ec) return true;
236256
#else // Asio < 1.10.8 didn't have ssl::error::stream_truncated
237257
if (boost::system::error_code(ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SHORT_READ),
@@ -259,14 +279,17 @@ class asio_connection
259279
}
260280

261281
template<typename HandshakeHandler, typename CertificateHandler>
262-
void async_handshake(boost::asio::ssl::stream_base::handshake_type type,
282+
void async_handshake(ssl_handshake_type_t type,
263283
const http_client_config& config,
264284
const HandshakeHandler& handshake_handler,
265285
const CertificateHandler& cert_handler)
266286
{
267287
std::lock_guard<std::mutex> lock(m_socket_lock);
268288
assert(is_ssl());
269289

290+
#if !defined(CPPREST_BOTAN_SSL)
291+
// This is configured via the Botan::TLS::Context callback in the Botan case
292+
270293
// Check to turn on/off server certificate verification.
271294
if (config.validate_certificates())
272295
{
@@ -283,7 +306,7 @@ class asio_connection
283306
{
284307
SSL_set_tlsext_host_name(m_ssl_stream->native_handle(), &m_cn_hostname[0]);
285308
}
286-
309+
#endif
287310
m_ssl_stream->async_handshake(type, handshake_handler);
288311
}
289312

@@ -337,7 +360,7 @@ class asio_connection
337360
// as normal message processing.
338361
std::mutex m_socket_lock;
339362
tcp::socket m_socket;
340-
std::unique_ptr<boost::asio::ssl::stream<tcp::socket&>> m_ssl_stream;
363+
std::unique_ptr<ssl_stream_t> m_ssl_stream;
341364
std::string m_cn_hostname;
342365

343366
bool m_is_reused;
@@ -1062,10 +1085,13 @@ class asio_context final : public request_context, public std::enable_shared_fro
10621085
{
10631086
const auto weakCtx = std::weak_ptr<asio_context>(shared_from_this());
10641087
m_connection->async_handshake(
1065-
boost::asio::ssl::stream_base::client,
1088+
ssl_handshake_type_t::client,
10661089
m_http_client->client_config(),
10671090
boost::bind(&asio_context::handle_handshake, shared_from_this(), boost::asio::placeholders::error),
10681091

1092+
#if defined(CPPREST_BOTAN_SSL)
1093+
false // unused
1094+
#else
10691095
// Use a weak_ptr since the verify_callback is stored until the connection is
10701096
// destroyed. This avoids creating a circular reference since we pool connection
10711097
// objects.
@@ -1076,7 +1102,9 @@ class asio_context final : public request_context, public std::enable_shared_fro
10761102
return this_request->handle_cert_verification(preverified, verify_context);
10771103
}
10781104
return false;
1079-
});
1105+
}
1106+
#endif
1107+
);
10801108
}
10811109
else
10821110
{
@@ -1096,7 +1124,7 @@ class asio_context final : public request_context, public std::enable_shared_fro
10961124
}
10971125
else
10981126
{
1099-
report_error("Error in SSL handshake", ec, httpclient_errorcode_context::handshake);
1127+
report_error("Error in SSL handshake: " + ec.message(), ec, httpclient_errorcode_context::handshake);
11001128
}
11011129
}
11021130

Release/tests/functional/http/client/client_construction.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ SUITE(client_construction)
181181
http_client_config config;
182182
bool called = false;
183183

184-
config.set_ssl_context_callback([&called](boost::asio::ssl::context& ctx) { called = true; });
184+
config.set_ssl_context_callback([&called](http_client::ssl_context& ctx) { called = true; });
185185

186186
http_client client("https://www.google.com/", config);
187187

@@ -202,7 +202,7 @@ SUITE(client_construction)
202202
http_client_config config;
203203
bool called = false;
204204

205-
config.set_ssl_context_callback([&called](boost::asio::ssl::context& ctx) { called = true; });
205+
config.set_ssl_context_callback([&called](http_client::ssl_context& ctx) { called = true; });
206206

207207
http_client client("http://www.google.com/", config);
208208

Release/tests/functional/http/listener/listener_construction_tests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ SUITE(listener_construction_tests)
425425
}
426426
}
427427

428-
#if !defined(_WIN32) && !defined(__cplusplus_winrt) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO)
428+
#if (!defined(_WIN32) && !defined(__cplusplus_winrt) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO)) && !defined(CPPREST_BOTAN_SSL)
429429

430430
TEST_FIXTURE(uri_address, create_https_listener_get, "Ignore", "github 209")
431431
{

0 commit comments

Comments
 (0)