Skip to content

Commit 413f099

Browse files
committed
Merge pull request cpp-netlib#602 from theopolis/master
[cpp-netlib#600] Add TLS SNI hostname to client options
2 parents c4f0567 + 1e18406 commit 413f099

File tree

12 files changed

+122
-93
lines changed

12 files changed

+122
-93
lines changed

boost/network/protocol/http/client/async_impl.hpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ struct async_client
3232
typedef typename string<Tag>::type string_type;
3333

3434
typedef std::function<void(boost::iterator_range<char const*> const&,
35-
std::error_code const&)> body_callback_function_type;
35+
std::error_code const&)>
36+
body_callback_function_type;
3637

3738
typedef std::function<bool(string_type&)> body_generator_function_type;
3839

@@ -43,11 +44,11 @@ struct async_client
4344
optional<string_type> verify_path,
4445
optional<string_type> certificate_file,
4546
optional<string_type> private_key_file,
46-
optional<string_type> ciphers, long ssl_options)
47+
optional<string_type> ciphers,
48+
optional<string_type> sni_hostname, long ssl_options)
4749
: connection_base(cache_resolved, follow_redirect, timeout),
48-
service_ptr(service.get()
49-
? service
50-
: std::make_shared<asio::io_service>()),
50+
service_ptr(service.get() ? service
51+
: std::make_shared<asio::io_service>()),
5152
service_(*service_ptr),
5253
resolver_(service_),
5354
sentinel_(new asio::io_service::work(service_)),
@@ -56,12 +57,13 @@ struct async_client
5657
certificate_file_(std::move(certificate_file)),
5758
private_key_file_(std::move(private_key_file)),
5859
ciphers_(std::move(ciphers)),
60+
sni_hostname_(std::move(sni_hostname)),
5961
ssl_options_(ssl_options),
6062
always_verify_peer_(always_verify_peer) {
6163
connection_base::resolver_strand_.reset(
6264
new asio::io_service::strand(service_));
6365
if (!service)
64-
lifetime_thread_.reset(new std::thread([this] () { service_.run(); }));
66+
lifetime_thread_.reset(new std::thread([this]() { service_.run(); }));
6567
}
6668

6769
~async_client() throw() = default;
@@ -82,7 +84,7 @@ struct async_client
8284
connection_ = connection_base::get_connection(
8385
resolver_, request_, always_verify_peer_, certificate_filename_,
8486
verify_path_, certificate_file_, private_key_file_, ciphers_,
85-
ssl_options_);
87+
sni_hostname_, ssl_options_);
8688
return connection_->send_request(method, request_, get_body, callback,
8789
generator);
8890
}
@@ -97,6 +99,7 @@ struct async_client
9799
optional<string_type> certificate_file_;
98100
optional<string_type> private_key_file_;
99101
optional<string_type> ciphers_;
102+
optional<string_type> sni_hostname_;
100103
long ssl_options_;
101104
bool always_verify_peer_;
102105
};

boost/network/protocol/http/client/connection/async_base.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,15 @@ struct async_connection_base {
4646
optional<string_type> certificate_file = optional<string_type>(),
4747
optional<string_type> private_key_file = optional<string_type>(),
4848
optional<string_type> ciphers = optional<string_type>(),
49+
optional<string_type> sni_hostname = optional<string_type>(),
4950
long ssl_options = 0) {
5051
typedef http_async_connection<Tag, version_major, version_minor>
5152
async_connection;
5253
typedef typename delegate_factory<Tag>::type delegate_factory_type;
5354
auto delegate = delegate_factory_type::new_connection_delegate(
5455
resolver.get_io_service(), https, always_verify_peer,
5556
certificate_filename, verify_path, certificate_file, private_key_file,
56-
ciphers, ssl_options);
57+
ciphers, sni_hostname, ssl_options);
5758
auto temp = std::make_shared<async_connection>(
5859
resolver, resolve, follow_redirect, timeout, std::move(delegate));
5960
BOOST_ASSERT(temp != nullptr);

boost/network/protocol/http/client/connection/connection_delegate_factory.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,14 @@ struct connection_delegate_factory {
3838
optional<string_type> certificate_filename,
3939
optional<string_type> verify_path, optional<string_type> certificate_file,
4040
optional<string_type> private_key_file, optional<string_type> ciphers,
41-
long ssl_options) {
41+
optional<string_type> sni_hostname, long ssl_options) {
4242
connection_delegate_ptr delegate;
4343
if (https) {
4444
#ifdef BOOST_NETWORK_ENABLE_HTTPS
4545
delegate = std::make_shared<ssl_delegate>(
4646
service, always_verify_peer, certificate_filename, verify_path,
47-
certificate_file, private_key_file, ciphers, ssl_options);
47+
certificate_file, private_key_file, ciphers, sni_hostname,
48+
ssl_options);
4849
#else
4950
BOOST_THROW_EXCEPTION(std::runtime_error("HTTPS not supported."));
5051
#endif /* BOOST_NETWORK_ENABLE_HTTPS */

boost/network/protocol/http/client/connection/ssl_delegate.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ struct ssl_delegate : public connection_delegate,
2929
optional<std::string> verify_path,
3030
optional<std::string> certificate_file,
3131
optional<std::string> private_key_file,
32-
optional<std::string> ciphers, long ssl_options);
32+
optional<std::string> ciphers,
33+
optional<std::string> sni_hostname, long ssl_options);
3334

3435
void connect(asio::ip::tcp::endpoint &endpoint, std::string host,
3536
std::uint16_t source_port,
@@ -50,6 +51,7 @@ struct ssl_delegate : public connection_delegate,
5051
optional<std::string> certificate_file_;
5152
optional<std::string> private_key_file_;
5253
optional<std::string> ciphers_;
54+
optional<std::string> sni_hostname_;
5355
long ssl_options_;
5456
std::unique_ptr<asio::ssl::context> context_;
5557
std::unique_ptr<asio::ip::tcp::socket> tcp_socket_;

boost/network/protocol/http/client/connection/ssl_delegate.ipp

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@ boost::network::http::impl::ssl_delegate::ssl_delegate(
1717
optional<std::string> certificate_filename,
1818
optional<std::string> verify_path, optional<std::string> certificate_file,
1919
optional<std::string> private_key_file, optional<std::string> ciphers,
20-
long ssl_options)
20+
optional<std::string> sni_hostname, long ssl_options)
2121
: service_(service),
2222
certificate_filename_(std::move(certificate_filename)),
2323
verify_path_(std::move(verify_path)),
2424
certificate_file_(std::move(certificate_file)),
2525
private_key_file_(std::move(private_key_file)),
2626
ciphers_(std::move(ciphers)),
27+
sni_hostname_(std::move(sni_hostname)),
2728
ssl_options_(ssl_options),
2829
always_verify_peer_(always_verify_peer) {}
2930

@@ -58,25 +59,23 @@ void boost::network::http::impl::ssl_delegate::connect(
5859
}
5960
}
6061
if (certificate_file_)
61-
context_->use_certificate_file(*certificate_file_,
62-
asio::ssl::context::pem);
62+
context_->use_certificate_file(*certificate_file_, asio::ssl::context::pem);
6363
if (private_key_file_)
64-
context_->use_private_key_file(*private_key_file_,
65-
asio::ssl::context::pem);
64+
context_->use_private_key_file(*private_key_file_, asio::ssl::context::pem);
6665

6766
tcp_socket_.reset(new asio::ip::tcp::socket(
6867
service_, asio::ip::tcp::endpoint(asio::ip::tcp::v4(), source_port)));
6968
socket_.reset(new asio::ssl::stream<asio::ip::tcp::socket &>(
7069
*(tcp_socket_.get()), *context_));
7170

71+
if (sni_hostname_)
72+
SSL_set_tlsext_host_name(socket_->native_handle(), sni_hostname_->c_str());
7273
if (always_verify_peer_)
7374
socket_->set_verify_callback(asio::ssl::rfc2818_verification(host));
7475
auto self = this->shared_from_this();
7576
socket_->lowest_layer().async_connect(
7677
endpoint,
77-
[=] (std::error_code const &ec) {
78-
self->handle_connected(ec, handler);
79-
});
78+
[=](std::error_code const &ec) { self->handle_connected(ec, handler); });
8079
}
8180

8281
void boost::network::http::impl::ssl_delegate::handle_connected(
@@ -104,8 +103,8 @@ void boost::network::http::impl::ssl_delegate::read_some(
104103
void boost::network::http::impl::ssl_delegate::disconnect() {
105104
if (socket_.get() && socket_->lowest_layer().is_open()) {
106105
std::error_code ignored;
107-
socket_->lowest_layer().shutdown(
108-
asio::ip::tcp::socket::shutdown_both, ignored);
106+
socket_->lowest_layer().shutdown(asio::ip::tcp::socket::shutdown_both,
107+
ignored);
109108
if (!ignored) {
110109
socket_->lowest_layer().close(ignored);
111110
}

boost/network/protocol/http/client/connection/sync_base.hpp

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ struct sync_connection_base_impl {
3939

4040
template <class Socket>
4141
void init_socket(Socket& socket_, resolver_type& resolver_,
42-
string_type /*unused*/const& hostname, string_type const& port,
43-
resolver_function_type resolve_) {
42+
string_type /*unused*/ const& hostname,
43+
string_type const& port, resolver_function_type resolve_) {
4444
using asio::ip::tcp;
4545
std::error_code error = asio::error::host_not_found;
4646
typename resolver_type::iterator endpoint_iterator, end;
@@ -100,7 +100,7 @@ struct sync_connection_base_impl {
100100
}
101101

102102
template <class Socket>
103-
void send_request_impl(Socket& socket_, string_type /*unused*/const& method,
103+
void send_request_impl(Socket& socket_, string_type /*unused*/ const& method,
104104
asio::streambuf& request_buffer) {
105105
// TODO(dberris): review parameter necessity.
106106
(void)method;
@@ -118,8 +118,8 @@ struct sync_connection_base_impl {
118118
std::error_code error;
119119
if (response_buffer.size() > 0) body_stream << &response_buffer;
120120

121-
while (asio::read(socket_, response_buffer,
122-
asio::transfer_at_least(1), error)) {
121+
while (asio::read(socket_, response_buffer, asio::transfer_at_least(1),
122+
error)) {
123123
body_stream << &response_buffer;
124124
}
125125
}
@@ -171,8 +171,7 @@ struct sync_connection_base_impl {
171171
read(socket_, response_buffer,
172172
asio::transfer_at_least(bytes_to_read), error);
173173
if (chunk_bytes_read == 0) {
174-
if (error != asio::error::eof)
175-
throw std::system_error(error);
174+
if (error != asio::error::eof) throw std::system_error(error);
176175
stopping_inner = true;
177176
}
178177
}
@@ -195,14 +194,14 @@ struct sync_connection_base_impl {
195194
} else {
196195
size_t already_read = response_buffer.size();
197196
if (already_read) body_stream << &response_buffer;
198-
size_t length = std::stoul(std::begin(content_length_range)->second) -
199-
already_read;
200-
if (length == 0) { return;
201-
}
197+
size_t length =
198+
std::stoul(std::begin(content_length_range)->second) - already_read;
199+
if (length == 0) {
200+
return;
201+
}
202202
size_t bytes_read = 0;
203203
while ((bytes_read = asio::read(socket_, response_buffer,
204-
asio::transfer_at_least(1),
205-
error))) {
204+
asio::transfer_at_least(1), error))) {
206205
body_stream << &response_buffer;
207206
length -= bytes_read;
208207
if ((length <= 0) || error) break;
@@ -223,7 +222,7 @@ struct sync_connection_base_impl {
223222
} else {
224223
read_body_transfer_chunk_encoding(socket_, response_, response_buffer,
225224
body_stream);
226-
}
225+
}
227226
} else {
228227
throw std::runtime_error("Unsupported HTTP version number.");
229228
}
@@ -249,14 +248,15 @@ struct sync_connection_base {
249248
new_connection(
250249
resolver_type& resolver, resolver_function_type resolve, bool https,
251250
bool always_verify_peer, int timeout,
252-
optional<string_type> /*unused*/const& certificate_filename =
251+
optional<string_type> /*unused*/ const& certificate_filename =
253252
optional<string_type>(),
254253
optional<string_type> const& verify_path = optional<string_type>(),
255254
optional<string_type> const& certificate_file =
256255
optional<string_type>(),
257256
optional<string_type> const& private_key_file =
258257
optional<string_type>(),
259258
optional<string_type> const& ciphers = optional<string_type>(),
259+
optional<string_type> const& sni_hostname = optional<string_type>(),
260260
long ssl_options = 0) {
261261
if (https) {
262262
#ifdef BOOST_NETWORK_ENABLE_HTTPS
@@ -265,7 +265,7 @@ struct sync_connection_base {
265265
new https_sync_connection<Tag, version_major, version_minor>(
266266
resolver, resolve, always_verify_peer, timeout,
267267
certificate_filename, verify_path, certificate_file,
268-
private_key_file, ciphers, ssl_options));
268+
private_key_file, ciphers, sni_hostname, ssl_options));
269269
#else
270270
throw std::runtime_error("HTTPS not supported.");
271271
#endif

boost/network/protocol/http/client/connection/sync_ssl.hpp

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -50,20 +50,20 @@ struct https_sync_connection
5050
https_sync_connection(
5151
resolver_type& resolver, resolver_function_type resolve,
5252
bool always_verify_peer, int timeout,
53-
optional<string_type> /*unused*/const& certificate_filename =
53+
optional<string_type> /*unused*/ const& certificate_filename =
5454
optional<string_type>(),
5555
optional<string_type> const& verify_path = optional<string_type>(),
5656
optional<string_type> const& certificate_file = optional<string_type>(),
5757
optional<string_type> const& private_key_file = optional<string_type>(),
5858
optional<string_type> const& ciphers = optional<string_type>(),
59+
optional<string_type> const& sni_hostname = optional<string_type>(),
5960
long ssl_options = 0)
6061
: connection_base(),
6162
timeout_(timeout),
6263
timer_(resolver.get_io_service()),
6364
resolver_(resolver),
6465
resolve_(std::move(resolve)),
65-
context_(resolver.get_io_service(),
66-
asio::ssl::context::sslv23_client),
66+
context_(resolver.get_io_service(), asio::ssl::context::sslv23_client),
6767
socket_(resolver.get_io_service(), context_) {
6868
if (ciphers) {
6969
::SSL_CTX_set_cipher_list(context_.native_handle(), ciphers->c_str());
@@ -86,20 +86,21 @@ struct https_sync_connection
8686
context_.set_verify_mode(asio::ssl::context_base::verify_none);
8787
}
8888
if (certificate_file)
89-
context_.use_certificate_file(*certificate_file,
90-
asio::ssl::context::pem);
89+
context_.use_certificate_file(*certificate_file, asio::ssl::context::pem);
9190
if (private_key_file)
92-
context_.use_private_key_file(*private_key_file,
93-
asio::ssl::context::pem);
91+
context_.use_private_key_file(*private_key_file, asio::ssl::context::pem);
92+
if (sni_hostname)
93+
SSL_set_tlsext_host_name(socket_.native_handle(), sni_hostname->c_str());
9494
}
9595

96-
void init_socket(string_type /*unused*/const& hostname, string_type const& port) {
96+
void init_socket(string_type /*unused*/ const& hostname,
97+
string_type const& port) {
9798
connection_base::init_socket(socket_.lowest_layer(), resolver_, hostname,
9899
port, resolve_);
99100
socket_.handshake(asio::ssl::stream_base::client);
100101
}
101102

102-
void send_request_impl(string_type /*unused*/const& method,
103+
void send_request_impl(string_type /*unused*/ const& method,
103104
basic_request<Tag> const& request_,
104105
body_generator_function_type generator) {
105106
asio::streambuf request_buffer;
@@ -120,9 +121,8 @@ struct https_sync_connection
120121
if (timeout_ > 0) {
121122
timer_.expires_from_now(boost::posix_time::seconds(timeout_));
122123
auto self = this->shared_from_this();
123-
timer_.async_wait([=] (std::error_code const &ec) {
124-
self->handle_timeout(ec);
125-
});
124+
timer_.async_wait(
125+
[=](std::error_code const& ec) { self->handle_timeout(ec); });
126126
}
127127
}
128128

@@ -141,7 +141,8 @@ struct https_sync_connection
141141
connection_base::read_body(socket_, response_, response_buffer);
142142
typename headers_range<basic_response<Tag> >::type connection_range =
143143
headers(response_)["Connection"];
144-
if (version_major == 1 && version_minor == 1 && !boost::empty(connection_range) &&
144+
if (version_major == 1 && version_minor == 1 &&
145+
!boost::empty(connection_range) &&
145146
boost::iequals(std::begin(connection_range)->second, "close")) {
146147
close_socket();
147148
} else if (version_major == 1 && version_minor == 0) {
@@ -156,16 +157,19 @@ struct https_sync_connection
156157
std::error_code ignored;
157158
socket_.lowest_layer().shutdown(asio::ip::tcp::socket::shutdown_both,
158159
ignored);
159-
if (ignored) { return; }
160+
if (ignored) {
161+
return;
162+
}
160163
socket_.lowest_layer().close(ignored);
161164
}
162165

163166
~https_sync_connection() { close_socket(); }
164167

165168
private:
166169
void handle_timeout(std::error_code const& ec) {
167-
if (!ec) { close_socket();
168-
}
170+
if (!ec) {
171+
close_socket();
172+
}
169173
}
170174

171175
int timeout_;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy