Skip to content

Commit 807fa51

Browse files
maingohdeanberris
authored andcommitted
Request sni hostname (#787)
* Ability to set a sni_hostname at the request level * Better test * Test only if https enabled
1 parent 7ab74c5 commit 807fa51

File tree

8 files changed

+63
-21
lines changed

8 files changed

+63
-21
lines changed

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

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,14 @@ struct http_async_connection
101101
string_type host_ = host(request);
102102
std::uint16_t source_port = request.source_port();
103103

104+
auto sni_hostname = request.sni_hostname();
105+
104106
auto self = this->shared_from_this();
105107
resolve_(resolver_, host_, port_,
106108
request_strand_.wrap(
107109
[=] (boost::system::error_code const &ec,
108110
resolver_iterator_pair endpoint_range) {
109-
self->handle_resolved(host_, port_, source_port, get_body,
111+
self->handle_resolved(host_, port_, source_port, sni_hostname, get_body,
110112
callback, generator, ec, endpoint_range);
111113
}));
112114
if (timeout_ > 0) {
@@ -139,7 +141,7 @@ struct http_async_connection
139141
}
140142

141143
void handle_resolved(string_type host, std::uint16_t port,
142-
std::uint16_t source_port, bool get_body,
144+
std::uint16_t source_port, optional<string_type> sni_hostname, bool get_body,
143145
body_callback_function_type callback,
144146
body_generator_function_type generator,
145147
boost::system::error_code const& ec,
@@ -151,10 +153,10 @@ struct http_async_connection
151153
boost::asio::ip::tcp::endpoint endpoint(iter->endpoint().address(), port);
152154
auto self = this->shared_from_this();
153155
delegate_->connect(
154-
endpoint, host, source_port,
156+
endpoint, host, source_port, sni_hostname,
155157
request_strand_.wrap([=] (boost::system::error_code const &ec) {
156158
auto iter_copy = iter;
157-
self->handle_connected(host, port, source_port, get_body, callback,
159+
self->handle_connected(host, port, source_port, sni_hostname, get_body, callback,
158160
generator, std::make_pair(++iter_copy, resolver_iterator()), ec);
159161
}));
160162
} else {
@@ -163,7 +165,7 @@ struct http_async_connection
163165
}
164166

165167
void handle_connected(string_type host, std::uint16_t port,
166-
std::uint16_t source_port, bool get_body,
168+
std::uint16_t source_port, optional<string_type> sni_hostname, bool get_body,
167169
body_callback_function_type callback,
168170
body_generator_function_type generator,
169171
resolver_iterator_pair endpoint_range,
@@ -186,10 +188,10 @@ struct http_async_connection
186188
boost::asio::ip::tcp::endpoint endpoint(iter->endpoint().address(), port);
187189
auto self = this->shared_from_this();
188190
delegate_->connect(
189-
endpoint, host, source_port,
191+
endpoint, host, source_port, sni_hostname,
190192
request_strand_.wrap([=] (boost::system::error_code const &ec) {
191193
auto iter_copy = iter;
192-
self->handle_connected(host, port, source_port, get_body, callback,
194+
self->handle_connected(host, port, source_port, sni_hostname, get_body, callback,
193195
generator, std::make_pair(++iter_copy, resolver_iterator()),
194196
ec);
195197
}));

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <functional>
1212
#include <boost/asio/ip/tcp.hpp>
1313
#include <boost/asio/streambuf.hpp>
14+
#include <boost/optional.hpp>
1415

1516
namespace boost {
1617
namespace network {
@@ -19,7 +20,7 @@ namespace impl {
1920

2021
struct connection_delegate {
2122
virtual void connect(boost::asio::ip::tcp::endpoint &endpoint, std::string host,
22-
std::uint16_t source_port,
23+
std::uint16_t source_port, optional<std::string> sni_hostname,
2324
std::function<void(boost::system::error_code const &)> handler) = 0;
2425
virtual void write(
2526
boost::asio::streambuf &command_streambuf,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ struct normal_delegate : connection_delegate {
2525
explicit normal_delegate(boost::asio::io_service &service);
2626

2727
void connect(boost::asio::ip::tcp::endpoint &endpoint, std::string host,
28-
std::uint16_t source_port,
28+
std::uint16_t source_port, optional<std::string> sni_hostname,
2929
std::function<void(boost::system::error_code const &)> handler) override;
3030
void write(boost::asio::streambuf &command_streambuf,
3131
std::function<void(boost::system::error_code const &, size_t)> handler)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ boost::network::http::impl::normal_delegate::normal_delegate(
2121

2222
void boost::network::http::impl::normal_delegate::connect(
2323
boost::asio::ip::tcp::endpoint &endpoint, std::string host,
24-
std::uint16_t source_port,
24+
std::uint16_t source_port, optional<std::string> sni_hostname,
2525
std::function<void(boost::system::error_code const &)> handler) {
2626

2727
// TODO(dberris): review parameter necessity.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ struct ssl_delegate : public connection_delegate,
3333
optional<std::string> sni_hostname, long ssl_options);
3434

3535
void connect(boost::asio::ip::tcp::endpoint &endpoint, std::string host,
36-
std::uint16_t source_port,
36+
std::uint16_t source_port, optional<std::string> sni_hostname,
3737
std::function<void(boost::system::error_code const &)> handler) override;
3838
void write(
3939
boost::asio::streambuf &command_streambuf,

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,9 @@ boost::network::http::impl::ssl_delegate::ssl_delegate(
3030

3131
void boost::network::http::impl::ssl_delegate::connect(
3232
boost::asio::ip::tcp::endpoint &endpoint, std::string host,
33-
std::uint16_t source_port,
33+
std::uint16_t source_port, optional<std::string> sni_hostname,
3434
std::function<void(boost::system::error_code const &)> handler) {
35+
3536
context_.reset(
3637
new boost::asio::ssl::context(boost::asio::ssl::context::method::sslv23_client));
3738
if (ciphers_) {
@@ -71,8 +72,13 @@ void boost::network::http::impl::ssl_delegate::connect(
7172
socket_.reset(new boost::asio::ssl::stream<boost::asio::ip::tcp::socket &>(
7273
*(tcp_socket_.get()), *context_));
7374

74-
if (sni_hostname_)
75+
if (sni_hostname) { // at request level
76+
SSL_set_tlsext_host_name(socket_->native_handle(), sni_hostname->c_str());
77+
} else if (sni_hostname_) { // at client level
7578
SSL_set_tlsext_host_name(socket_->native_handle(), sni_hostname_->c_str());
79+
}
80+
81+
7682
if (always_verify_peer_)
7783
socket_->set_verify_callback(boost::asio::ssl::rfc2818_verification(host));
7884
auto self = this->shared_from_this();

boost/network/protocol/http/impl/request.hpp

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,29 +50,32 @@ namespace http {
5050
*/
5151
template <class Tag>
5252
struct basic_request : public basic_message<Tag> {
53-
mutable boost::network::uri::uri uri_;
54-
std::uint16_t source_port_;
55-
typedef basic_message<Tag> base_type;
56-
5753
public:
5854
typedef Tag tag;
5955
typedef typename string<tag>::type string_type;
6056
typedef std::uint16_t port_type;
6157

58+
private:
59+
mutable boost::network::uri::uri uri_;
60+
std::uint16_t source_port_;
61+
optional<string_type> sni_hostname_;
62+
typedef basic_message<Tag> base_type;
63+
64+
public:
6265
explicit basic_request(string_type const& uri_)
63-
: uri_(uri_), source_port_(0) {}
66+
: uri_(uri_), source_port_(0), sni_hostname_() {}
6467

6568
explicit basic_request(boost::network::uri::uri const& uri_)
66-
: uri_(uri_), source_port_(0) {}
69+
: uri_(uri_), source_port_(0), sni_hostname_() {}
6770

6871
void uri(string_type const& new_uri) { uri_ = new_uri; }
6972

7073
void uri(boost::network::uri::uri const& new_uri) { uri_ = new_uri; }
7174

72-
basic_request() : base_type(), source_port_(0) {}
75+
basic_request() : base_type(), source_port_(0), sni_hostname_() {}
7376

7477
basic_request(basic_request const& other)
75-
: base_type(other), uri_(other.uri_), source_port_(other.source_port_) {}
78+
: base_type(other), uri_(other.uri_), source_port_(other.source_port_), sni_hostname_(other.sni_hostname_) {}
7679

7780
basic_request& operator=(basic_request rhs) {
7881
rhs.swap(*this);
@@ -85,6 +88,7 @@ struct basic_request : public basic_message<Tag> {
8588
base_ref.swap(this_ref);
8689
boost::swap(other.uri_, this->uri_);
8790
boost::swap(other.source_port_, this->source_port_);
91+
boost::swap(other.sni_hostname_, this->sni_hostname_);
8892
}
8993

9094
string_type const host() const { return uri_.host(); }
@@ -114,6 +118,10 @@ struct basic_request : public basic_message<Tag> {
114118
void source_port(const std::uint16_t port) { source_port_ = port; }
115119

116120
std::uint16_t source_port() const { return source_port_; }
121+
122+
void sni_hostname(string_type const &sni_hostname) { sni_hostname_ = sni_hostname; }
123+
124+
const optional<string_type> &sni_hostname() const { return sni_hostname_; }
117125
};
118126

119127
/** This is the implementation of a POD request type

libs/network/test/http/client_get_test.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,31 @@ TYPED_TEST(HTTPClientTest, GetHTTPSTest) {
4646
}
4747
}
4848

49+
TYPED_TEST(HTTPClientTest, GetRequestSNI) {
50+
using client = TypeParam;
51+
// need sni_hostname to be set
52+
typename client::request request("https://www.guide-du-chien.com/wp-content/uploads/2016/10/Beagle.jpg");
53+
typename client::response response;
54+
55+
// trying without setting sni_hostname
56+
ASSERT_NO_THROW(response = client().get(request));
57+
// raise "tlsv1 alert internal error"
58+
ASSERT_THROW(response.status(), std::exception_ptr);
59+
60+
// setting sni_hostname
61+
request.sni_hostname(request.host());
62+
ASSERT_NO_THROW(response = client().get(request));
63+
EXPECT_EQ(200u, response.status());
64+
65+
try {
66+
auto data = body(response);
67+
std::cout << "Body size: " << data.size() << std::endl;
68+
} catch (...) {
69+
FAIL() << "Caught exception while retrieving body from GET request";
70+
}
71+
72+
}
73+
4974
#endif
5075

5176
TYPED_TEST(HTTPClientTest, TemporaryClientObjectTest) {

0 commit comments

Comments
 (0)