asio: Clean up server API to explicitly set error code
This commit is contained in:
parent
94ca9705ef
commit
018e9eaf6d
|
@ -45,23 +45,23 @@ using namespace nghttp2::asio_http2::server;
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
try {
|
try {
|
||||||
// Check command line arguments.
|
// Check command line arguments.
|
||||||
if (argc < 3) {
|
if (argc < 4) {
|
||||||
std::cerr << "Usage: asio-sv <port> <threads> <private-key-file> "
|
std::cerr
|
||||||
<< "<cert-file>\n";
|
<< "Usage: asio-sv <address> <port> <threads> [<private-key-file> "
|
||||||
|
<< "<cert-file>]\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t port = std::stoi(argv[1]);
|
boost::system::error_code ec;
|
||||||
std::size_t num_threads = std::stoi(argv[2]);
|
|
||||||
|
std::string addr = argv[1];
|
||||||
|
std::string port = argv[2];
|
||||||
|
std::size_t num_threads = std::stoi(argv[3]);
|
||||||
|
|
||||||
http2 server;
|
http2 server;
|
||||||
|
|
||||||
server.num_threads(num_threads);
|
server.num_threads(num_threads);
|
||||||
|
|
||||||
if (argc >= 5) {
|
|
||||||
server.tls(argv[3], argv[4]);
|
|
||||||
}
|
|
||||||
|
|
||||||
server.handle("/", [](const request &req, const response &res) {
|
server.handle("/", [](const request &req, const response &res) {
|
||||||
res.write_head(200, {{"foo", {"bar"}}});
|
res.write_head(200, {{"foo", {"bar"}}});
|
||||||
res.end("hello, world\n");
|
res.end("hello, world\n");
|
||||||
|
@ -101,8 +101,22 @@ int main(int argc, char *argv[]) {
|
||||||
res.end("finally!\n");
|
res.end("finally!\n");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
server.listen_and_serve("*", port);
|
|
||||||
|
|
||||||
|
if (argc >= 6) {
|
||||||
|
boost::asio::ssl::context tls(boost::asio::ssl::context::sslv23);
|
||||||
|
tls.use_private_key_file(argv[4], boost::asio::ssl::context::pem);
|
||||||
|
tls.use_certificate_chain_file(argv[5]);
|
||||||
|
|
||||||
|
configure_tls_context_easy(ec, tls);
|
||||||
|
|
||||||
|
if (server.listen_and_serve(ec, tls, addr, port)) {
|
||||||
|
std::cerr << "error: " << ec.message() << std::endl;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (server.listen_and_serve(ec, addr, port)) {
|
||||||
|
std::cerr << "error: " << ec.message() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (std::exception &e) {
|
} catch (std::exception &e) {
|
||||||
std::cerr << "exception: " << e.what() << "\n";
|
std::cerr << "exception: " << e.what() << "\n";
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,24 +48,23 @@ using namespace nghttp2::asio_http2::server;
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
try {
|
try {
|
||||||
// Check command line arguments.
|
// Check command line arguments.
|
||||||
if (argc < 4) {
|
if (argc < 5) {
|
||||||
std::cerr << "Usage: asio-sv2 <port> <threads> <doc-root> "
|
std::cerr << "Usage: asio-sv2 <address> <port> <threads> <doc-root> "
|
||||||
<< "<private-key-file> <cert-file>\n";
|
<< "[<private-key-file> <cert-file>]\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t port = std::stoi(argv[1]);
|
boost::system::error_code ec;
|
||||||
std::size_t num_threads = std::stoi(argv[2]);
|
|
||||||
std::string docroot = argv[3];
|
std::string addr = argv[1];
|
||||||
|
std::string port = argv[2];
|
||||||
|
std::size_t num_threads = std::stoi(argv[3]);
|
||||||
|
std::string docroot = argv[4];
|
||||||
|
|
||||||
http2 server;
|
http2 server;
|
||||||
|
|
||||||
server.num_threads(num_threads);
|
server.num_threads(num_threads);
|
||||||
|
|
||||||
if (argc >= 6) {
|
|
||||||
server.tls(argv[4], argv[5]);
|
|
||||||
}
|
|
||||||
|
|
||||||
server.handle("/", [&docroot](const request &req, const response &res) {
|
server.handle("/", [&docroot](const request &req, const response &res) {
|
||||||
auto path = percent_decode(req.uri().path);
|
auto path = percent_decode(req.uri().path);
|
||||||
if (!check_path(path)) {
|
if (!check_path(path)) {
|
||||||
|
@ -99,8 +98,21 @@ int main(int argc, char *argv[]) {
|
||||||
res.end(file_generator_from_fd(fd));
|
res.end(file_generator_from_fd(fd));
|
||||||
});
|
});
|
||||||
|
|
||||||
server.listen_and_serve("*", port);
|
if (argc >= 7) {
|
||||||
|
boost::asio::ssl::context tls(boost::asio::ssl::context::sslv23);
|
||||||
|
tls.use_private_key_file(argv[5], boost::asio::ssl::context::pem);
|
||||||
|
tls.use_certificate_chain_file(argv[6]);
|
||||||
|
|
||||||
|
configure_tls_context_easy(ec, tls);
|
||||||
|
|
||||||
|
if (server.listen_and_serve(ec, tls, addr, port)) {
|
||||||
|
std::cerr << "error: " << ec.message() << std::endl;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (server.listen_and_serve(ec, addr, port)) {
|
||||||
|
std::cerr << "error: " << ec.message() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (std::exception &e) {
|
} catch (std::exception &e) {
|
||||||
std::cerr << "exception: " << e.what() << "\n";
|
std::cerr << "exception: " << e.what() << "\n";
|
||||||
}
|
}
|
||||||
|
|
|
@ -189,6 +189,7 @@ libnghttp2_asio_la_SOURCES = \
|
||||||
asio_server_stream.cc asio_server_stream.h \
|
asio_server_stream.cc asio_server_stream.h \
|
||||||
asio_server_serve_mux.cc asio_server_serve_mux.h \
|
asio_server_serve_mux.cc asio_server_serve_mux.h \
|
||||||
asio_server_request_handler.cc asio_server_request_handler.h \
|
asio_server_request_handler.cc asio_server_request_handler.h \
|
||||||
|
asio_server_tls_context.cc asio_server_tls_context.h \
|
||||||
asio_client_session.cc \
|
asio_client_session.cc \
|
||||||
asio_client_session_impl.cc asio_client_session_impl.h \
|
asio_client_session_impl.cc asio_client_session_impl.h \
|
||||||
asio_client_session_tcp_impl.cc asio_client_session_tcp_impl.h \
|
asio_client_session_tcp_impl.cc asio_client_session_tcp_impl.h \
|
||||||
|
|
|
@ -45,14 +45,11 @@ namespace nghttp2 {
|
||||||
namespace asio_http2 {
|
namespace asio_http2 {
|
||||||
namespace server {
|
namespace server {
|
||||||
|
|
||||||
server::server(const std::string &address, uint16_t port,
|
server::server(std::size_t io_service_pool_size)
|
||||||
std::size_t io_service_pool_size, serve_mux &mux,
|
|
||||||
std::unique_ptr<boost::asio::ssl::context> ssl_ctx, int backlog)
|
|
||||||
: io_service_pool_(io_service_pool_size),
|
: io_service_pool_(io_service_pool_size),
|
||||||
signals_(io_service_pool_.get_io_service()),
|
signals_(io_service_pool_.get_io_service()),
|
||||||
tick_timer_(io_service_pool_.get_io_service(),
|
tick_timer_(io_service_pool_.get_io_service(),
|
||||||
boost::posix_time::seconds(1)),
|
boost::posix_time::seconds(1)) {
|
||||||
ssl_ctx_(std::move(ssl_ctx)), mux_(mux) {
|
|
||||||
// Register to handle the signals that indicate when the server should exit.
|
// Register to handle the signals that indicate when the server should exit.
|
||||||
// It is safe to register for the same signal multiple times in a program,
|
// It is safe to register for the same signal multiple times in a program,
|
||||||
// provided all registration for the specified signal is made through Asio.
|
// provided all registration for the specified signal is made through Asio.
|
||||||
|
@ -63,47 +60,85 @@ server::server(const std::string &address, uint16_t port,
|
||||||
#endif // defined(SIGQUIT)
|
#endif // defined(SIGQUIT)
|
||||||
signals_.async_wait([this](const boost::system::error_code &error,
|
signals_.async_wait([this](const boost::system::error_code &error,
|
||||||
int signal_number) { io_service_pool_.stop(); });
|
int signal_number) { io_service_pool_.stop(); });
|
||||||
|
}
|
||||||
|
|
||||||
// Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR).
|
boost::system::error_code
|
||||||
boost::asio::ip::tcp::resolver resolver(io_service_pool_.get_io_service());
|
server::listen_and_serve(boost::system::error_code &ec,
|
||||||
boost::asio::ip::tcp::resolver::query query(address, std::to_string(port));
|
boost::asio::ssl::context *tls_context,
|
||||||
|
const std::string &address, const std::string &port,
|
||||||
|
int backlog, serve_mux &mux) {
|
||||||
|
ec.clear();
|
||||||
|
|
||||||
for (auto itr = resolver.resolve(query);
|
if (bind_and_listen(ec, address, port, backlog)) {
|
||||||
itr != boost::asio::ip::tcp::resolver::iterator(); ++itr) {
|
return ec;
|
||||||
boost::asio::ip::tcp::endpoint endpoint = *itr;
|
|
||||||
auto acceptor =
|
|
||||||
boost::asio::ip::tcp::acceptor(io_service_pool_.get_io_service());
|
|
||||||
|
|
||||||
acceptor.open(endpoint.protocol());
|
|
||||||
acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
|
|
||||||
acceptor.bind(endpoint);
|
|
||||||
if (backlog == -1) {
|
|
||||||
acceptor.listen();
|
|
||||||
} else {
|
|
||||||
acceptor.listen(backlog);
|
|
||||||
}
|
|
||||||
acceptors_.push_back(std::move(acceptor));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &acceptor : acceptors_) {
|
for (auto &acceptor : acceptors_) {
|
||||||
start_accept(acceptor);
|
if (tls_context) {
|
||||||
|
start_accept(*tls_context, acceptor, mux);
|
||||||
|
} else {
|
||||||
|
start_accept(acceptor, mux);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
start_timer();
|
start_timer();
|
||||||
|
|
||||||
|
io_service_pool_.run();
|
||||||
|
|
||||||
|
return ec;
|
||||||
}
|
}
|
||||||
|
|
||||||
void server::run() { io_service_pool_.run(); }
|
boost::system::error_code server::bind_and_listen(boost::system::error_code &ec,
|
||||||
|
const std::string &address,
|
||||||
|
const std::string &port,
|
||||||
|
int backlog) {
|
||||||
|
// Open the acceptor with the option to reuse the address (i.e.
|
||||||
|
// SO_REUSEADDR).
|
||||||
|
tcp::resolver resolver(io_service_pool_.get_io_service());
|
||||||
|
tcp::resolver::query query(address, port);
|
||||||
|
auto it = resolver.resolve(query, ec);
|
||||||
|
if (ec) {
|
||||||
|
return ec;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; it != tcp::resolver::iterator(); ++it) {
|
||||||
|
tcp::endpoint endpoint = *it;
|
||||||
|
auto acceptor = tcp::acceptor(io_service_pool_.get_io_service());
|
||||||
|
|
||||||
|
if (acceptor.open(endpoint.protocol(), ec)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
acceptor.set_option(tcp::acceptor::reuse_address(true));
|
||||||
|
|
||||||
|
if (acceptor.bind(endpoint, ec)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (acceptor.listen(
|
||||||
|
backlog == -1 ? boost::asio::socket_base::max_connections : backlog,
|
||||||
|
ec)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
acceptors_.push_back(std::move(acceptor));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (acceptors_.empty()) {
|
||||||
|
return ec;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ec could have some errors since we may have failed to bind some
|
||||||
|
// interfaces.
|
||||||
|
ec.clear();
|
||||||
|
|
||||||
|
return ec;
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<std::string> cached_date;
|
std::shared_ptr<std::string> cached_date;
|
||||||
|
|
||||||
namespace {
|
|
||||||
void update_date() {
|
|
||||||
cached_date = std::make_shared<std::string>(util::http_date(time(nullptr)));
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
void server::start_timer() {
|
void server::start_timer() {
|
||||||
update_date();
|
cached_date = std::make_shared<std::string>(util::http_date(time(nullptr)));
|
||||||
|
|
||||||
tick_timer_.async_wait([this](const boost::system::error_code &e) {
|
tick_timer_.async_wait([this](const boost::system::error_code &e) {
|
||||||
tick_timer_.expires_at(tick_timer_.expires_at() +
|
tick_timer_.expires_at(tick_timer_.expires_at() +
|
||||||
|
@ -112,47 +147,43 @@ void server::start_timer() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket;
|
void server::start_accept(boost::asio::ssl::context &tls_context,
|
||||||
|
tcp::acceptor &acceptor, serve_mux &mux) {
|
||||||
|
auto new_connection = std::make_shared<connection<ssl_socket>>(
|
||||||
|
mux, io_service_pool_.get_io_service(), tls_context);
|
||||||
|
|
||||||
void server::start_accept(boost::asio::ip::tcp::acceptor &acceptor) {
|
acceptor.async_accept(new_connection->socket().lowest_layer(),
|
||||||
if (ssl_ctx_) {
|
[this, &tls_context, &acceptor, &mux, new_connection](
|
||||||
auto new_connection = std::make_shared<connection<ssl_socket>>(
|
const boost::system::error_code &e) {
|
||||||
mux_, io_service_pool_.get_io_service(), *ssl_ctx_);
|
if (!e) {
|
||||||
|
new_connection->socket().lowest_layer().set_option(tcp::no_delay(true));
|
||||||
|
new_connection->socket().async_handshake(
|
||||||
|
boost::asio::ssl::stream_base::server,
|
||||||
|
[new_connection](const boost::system::error_code &e) {
|
||||||
|
if (!e) {
|
||||||
|
new_connection->start();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
acceptor.async_accept(
|
start_accept(tls_context, acceptor, mux);
|
||||||
new_connection->socket().lowest_layer(),
|
});
|
||||||
[this, &acceptor, new_connection](const boost::system::error_code &e) {
|
}
|
||||||
if (!e) {
|
|
||||||
new_connection->socket().lowest_layer().set_option(
|
|
||||||
boost::asio::ip::tcp::no_delay(true));
|
|
||||||
new_connection->socket().async_handshake(
|
|
||||||
boost::asio::ssl::stream_base::server,
|
|
||||||
[new_connection](const boost::system::error_code &e) {
|
|
||||||
if (!e) {
|
|
||||||
new_connection->start();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
start_accept(acceptor);
|
void server::start_accept(tcp::acceptor &acceptor, serve_mux &mux) {
|
||||||
});
|
auto new_connection = std::make_shared<connection<tcp::socket>>(
|
||||||
} else {
|
mux, io_service_pool_.get_io_service());
|
||||||
auto new_connection =
|
|
||||||
std::make_shared<connection<boost::asio::ip::tcp::socket>>(
|
|
||||||
mux_, io_service_pool_.get_io_service());
|
|
||||||
|
|
||||||
acceptor.async_accept(
|
acceptor.async_accept(new_connection->socket(),
|
||||||
new_connection->socket(),
|
[this, &acceptor, &mux, new_connection](
|
||||||
[this, &acceptor, new_connection](const boost::system::error_code &e) {
|
const boost::system::error_code &e) {
|
||||||
if (!e) {
|
if (!e) {
|
||||||
new_connection->socket().set_option(
|
new_connection->socket().set_option(tcp::no_delay(true));
|
||||||
boost::asio::ip::tcp::no_delay(true));
|
new_connection->start();
|
||||||
new_connection->start();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
start_accept(acceptor);
|
start_accept(acceptor, mux);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace server
|
} // namespace server
|
||||||
|
|
|
@ -57,39 +57,49 @@ namespace server {
|
||||||
|
|
||||||
class serve_mux;
|
class serve_mux;
|
||||||
|
|
||||||
/// The top-level class of the HTTP server.
|
using boost::asio::ip::tcp;
|
||||||
|
|
||||||
|
using ssl_socket = boost::asio::ssl::stream<tcp::socket>;
|
||||||
|
|
||||||
class server : private boost::noncopyable {
|
class server : private boost::noncopyable {
|
||||||
public:
|
public:
|
||||||
/// Construct the server to listen on the specified TCP address and port, and
|
explicit server(std::size_t io_service_pool_size);
|
||||||
/// serve up files from the given directory.
|
|
||||||
explicit server(const std::string &address, uint16_t port,
|
|
||||||
std::size_t io_service_pool_size, serve_mux &mux_,
|
|
||||||
std::unique_ptr<boost::asio::ssl::context> ssl_ctx,
|
|
||||||
int backlog = -1);
|
|
||||||
|
|
||||||
/// Run the server's io_service loop.
|
boost::system::error_code
|
||||||
void run();
|
listen_and_serve(boost::system::error_code &ec,
|
||||||
|
boost::asio::ssl::context *tls_context,
|
||||||
|
const std::string &address, const std::string &port,
|
||||||
|
int backlog, serve_mux &mux);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Initiate an asynchronous accept operation.
|
/// Initiate an asynchronous accept operation.
|
||||||
void start_accept(boost::asio::ip::tcp::acceptor &acceptor);
|
void start_accept(tcp::acceptor &acceptor, serve_mux &mux);
|
||||||
|
/// Same as above but with tls_context
|
||||||
|
void start_accept(boost::asio::ssl::context &tls_context,
|
||||||
|
tcp::acceptor &acceptor, serve_mux &mux);
|
||||||
|
|
||||||
|
/// Resolves address and bind socket to the resolved addresses.
|
||||||
|
boost::system::error_code bind_and_listen(boost::system::error_code &ec,
|
||||||
|
const std::string &address,
|
||||||
|
const std::string &port,
|
||||||
|
int backlog);
|
||||||
|
|
||||||
void start_timer();
|
void start_timer();
|
||||||
|
|
||||||
/// The pool of io_service objects used to perform asynchronous operations.
|
/// The pool of io_service objects used to perform asynchronous
|
||||||
|
/// operations.
|
||||||
io_service_pool io_service_pool_;
|
io_service_pool io_service_pool_;
|
||||||
|
|
||||||
/// The signal_set is used to register for process termination notifications.
|
/// The signal_set is used to register for process termination
|
||||||
|
/// notifications.
|
||||||
boost::asio::signal_set signals_;
|
boost::asio::signal_set signals_;
|
||||||
|
|
||||||
boost::asio::deadline_timer tick_timer_;
|
boost::asio::deadline_timer tick_timer_;
|
||||||
|
|
||||||
/// Acceptor used to listen for incoming connections.
|
/// Acceptor used to listen for incoming connections.
|
||||||
std::vector<boost::asio::ip::tcp::acceptor> acceptors_;
|
std::vector<tcp::acceptor> acceptors_;
|
||||||
|
|
||||||
std::unique_ptr<boost::asio::ssl::context> ssl_ctx_;
|
std::unique_ptr<boost::asio::ssl::context> ssl_ctx_;
|
||||||
|
|
||||||
serve_mux &mux_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace server
|
} // namespace server
|
||||||
|
|
|
@ -40,16 +40,21 @@ http2::http2() : impl_(make_unique<http2_impl>()) {}
|
||||||
|
|
||||||
http2::~http2() {}
|
http2::~http2() {}
|
||||||
|
|
||||||
void http2::listen_and_serve(const std::string &address, uint16_t port) {
|
boost::system::error_code http2::listen_and_serve(boost::system::error_code &ec,
|
||||||
impl_->listen_and_serve(address, port);
|
const std::string &address,
|
||||||
|
const std::string &port) {
|
||||||
|
return impl_->listen_and_serve(ec, nullptr, address, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::system::error_code
|
||||||
|
http2::listen_and_serve(boost::system::error_code &ec,
|
||||||
|
boost::asio::ssl::context &tls_context,
|
||||||
|
const std::string &address, const std::string &port) {
|
||||||
|
return impl_->listen_and_serve(ec, &tls_context, address, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
void http2::num_threads(size_t num_threads) { impl_->num_threads(num_threads); }
|
void http2::num_threads(size_t num_threads) { impl_->num_threads(num_threads); }
|
||||||
|
|
||||||
void http2::tls(std::string private_key_file, std::string certificate_file) {
|
|
||||||
impl_->tls(std::move(private_key_file), std::move(certificate_file));
|
|
||||||
}
|
|
||||||
|
|
||||||
void http2::backlog(int backlog) { impl_->backlog(backlog); }
|
void http2::backlog(int backlog) { impl_->backlog(backlog); }
|
||||||
|
|
||||||
bool http2::handle(std::string pattern, request_cb cb) {
|
bool http2::handle(std::string pattern, request_cb cb) {
|
||||||
|
|
|
@ -39,66 +39,15 @@ namespace server {
|
||||||
|
|
||||||
http2_impl::http2_impl() : num_threads_(1), backlog_(-1) {}
|
http2_impl::http2_impl() : num_threads_(1), backlog_(-1) {}
|
||||||
|
|
||||||
namespace {
|
boost::system::error_code http2_impl::listen_and_serve(
|
||||||
std::vector<unsigned char> &get_alpn_token() {
|
boost::system::error_code &ec, boost::asio::ssl::context *tls_context,
|
||||||
static auto alpn_token = util::get_default_alpn();
|
const std::string &address, const std::string &port) {
|
||||||
return alpn_token;
|
return server(num_threads_)
|
||||||
}
|
.listen_and_serve(ec, tls_context, address, port, backlog_, mux_);
|
||||||
} // namespace
|
|
||||||
|
|
||||||
void http2_impl::listen_and_serve(const std::string &address, uint16_t port) {
|
|
||||||
std::unique_ptr<boost::asio::ssl::context> ssl_ctx;
|
|
||||||
|
|
||||||
if (!private_key_file_.empty() && !certificate_file_.empty()) {
|
|
||||||
ssl_ctx = make_unique<boost::asio::ssl::context>(
|
|
||||||
boost::asio::ssl::context::sslv23);
|
|
||||||
|
|
||||||
ssl_ctx->use_private_key_file(private_key_file_,
|
|
||||||
boost::asio::ssl::context::pem);
|
|
||||||
ssl_ctx->use_certificate_chain_file(certificate_file_);
|
|
||||||
|
|
||||||
auto ctx = ssl_ctx->native_handle();
|
|
||||||
|
|
||||||
SSL_CTX_set_options(ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
|
|
||||||
SSL_OP_NO_COMPRESSION |
|
|
||||||
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
|
|
||||||
SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_TICKET |
|
|
||||||
SSL_OP_CIPHER_SERVER_PREFERENCE);
|
|
||||||
SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
|
|
||||||
SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS);
|
|
||||||
|
|
||||||
SSL_CTX_set_cipher_list(ctx, ssl::DEFAULT_CIPHER_LIST);
|
|
||||||
|
|
||||||
auto ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
|
||||||
if (ecdh) {
|
|
||||||
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
|
|
||||||
EC_KEY_free(ecdh);
|
|
||||||
}
|
|
||||||
|
|
||||||
SSL_CTX_set_next_protos_advertised_cb(
|
|
||||||
ctx,
|
|
||||||
[](SSL *s, const unsigned char **data, unsigned int *len, void *arg) {
|
|
||||||
auto &token = get_alpn_token();
|
|
||||||
|
|
||||||
*data = token.data();
|
|
||||||
*len = token.size();
|
|
||||||
|
|
||||||
return SSL_TLSEXT_ERR_OK;
|
|
||||||
},
|
|
||||||
nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
server(address, port, num_threads_, mux_, std::move(ssl_ctx), backlog_).run();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void http2_impl::num_threads(size_t num_threads) { num_threads_ = num_threads; }
|
void http2_impl::num_threads(size_t num_threads) { num_threads_ = num_threads; }
|
||||||
|
|
||||||
void http2_impl::tls(std::string private_key_file,
|
|
||||||
std::string certificate_file) {
|
|
||||||
private_key_file_ = std::move(private_key_file);
|
|
||||||
certificate_file_ = std::move(certificate_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
void http2_impl::backlog(int backlog) { backlog_ = backlog; }
|
void http2_impl::backlog(int backlog) { backlog_ = backlog; }
|
||||||
|
|
||||||
bool http2_impl::handle(std::string pattern, request_cb cb) {
|
bool http2_impl::handle(std::string pattern, request_cb cb) {
|
||||||
|
|
|
@ -42,15 +42,15 @@ class server;
|
||||||
class http2_impl {
|
class http2_impl {
|
||||||
public:
|
public:
|
||||||
http2_impl();
|
http2_impl();
|
||||||
void listen_and_serve(const std::string &address, uint16_t port);
|
boost::system::error_code
|
||||||
|
listen_and_serve(boost::system::error_code &ec,
|
||||||
|
boost::asio::ssl::context *tls_context,
|
||||||
|
const std::string &address, const std::string &port);
|
||||||
void num_threads(size_t num_threads);
|
void num_threads(size_t num_threads);
|
||||||
void tls(std::string private_key_file, std::string certificate_file);
|
|
||||||
void backlog(int backlog);
|
void backlog(int backlog);
|
||||||
bool handle(std::string pattern, request_cb cb);
|
bool handle(std::string pattern, request_cb cb);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string private_key_file_;
|
|
||||||
std::string certificate_file_;
|
|
||||||
std::unique_ptr<server> server_;
|
std::unique_ptr<server> server_;
|
||||||
std::size_t num_threads_;
|
std::size_t num_threads_;
|
||||||
int backlog_;
|
int backlog_;
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
* nghttp2 - HTTP/2 C Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "asio_server_tls_context.h"
|
||||||
|
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
|
||||||
|
#include <boost/asio/ssl.hpp>
|
||||||
|
|
||||||
|
#include "ssl.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
namespace nghttp2 {
|
||||||
|
namespace asio_http2 {
|
||||||
|
namespace server {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
std::vector<unsigned char> &get_alpn_token() {
|
||||||
|
static auto alpn_token = util::get_default_alpn();
|
||||||
|
return alpn_token;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
boost::system::error_code
|
||||||
|
configure_tls_context_easy(boost::system::error_code &ec,
|
||||||
|
boost::asio::ssl::context &tls_context) {
|
||||||
|
ec.clear();
|
||||||
|
|
||||||
|
auto ctx = tls_context.native_handle();
|
||||||
|
|
||||||
|
SSL_CTX_set_options(ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
|
||||||
|
SSL_OP_NO_COMPRESSION |
|
||||||
|
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
|
||||||
|
SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_TICKET |
|
||||||
|
SSL_OP_CIPHER_SERVER_PREFERENCE);
|
||||||
|
SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
|
||||||
|
SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS);
|
||||||
|
|
||||||
|
SSL_CTX_set_cipher_list(ctx, ssl::DEFAULT_CIPHER_LIST);
|
||||||
|
|
||||||
|
auto ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
||||||
|
if (ecdh) {
|
||||||
|
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
|
||||||
|
EC_KEY_free(ecdh);
|
||||||
|
}
|
||||||
|
|
||||||
|
SSL_CTX_set_next_protos_advertised_cb(
|
||||||
|
ctx,
|
||||||
|
[](SSL *s, const unsigned char **data, unsigned int *len, void *arg) {
|
||||||
|
auto &token = get_alpn_token();
|
||||||
|
|
||||||
|
*data = token.data();
|
||||||
|
*len = token.size();
|
||||||
|
|
||||||
|
return SSL_TLSEXT_ERR_OK;
|
||||||
|
},
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
return ec;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace server
|
||||||
|
} // namespace asio_http2
|
||||||
|
} // namespace nghttp2
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* nghttp2 - HTTP/2 C Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef ASIO_SERVER_TLS_CONTEXT_H
|
||||||
|
#define ASIO_SERVER_TLS_CONTEXT_H
|
||||||
|
|
||||||
|
#include "nghttp2_config.h"
|
||||||
|
|
||||||
|
#include <nghttp2/asio_http2_server.h>
|
||||||
|
|
||||||
|
#endif // ASIO_SERVER_TLS_CONTEXT_H
|
|
@ -127,8 +127,17 @@ public:
|
||||||
~http2();
|
~http2();
|
||||||
|
|
||||||
// Starts listening connection on given address and port and serves
|
// Starts listening connection on given address and port and serves
|
||||||
// incoming requests.
|
// incoming requests in cleartext TCP connection.
|
||||||
void listen_and_serve(const std::string &address, uint16_t port);
|
boost::system::error_code listen_and_serve(boost::system::error_code &ec,
|
||||||
|
const std::string &address,
|
||||||
|
const std::string &port);
|
||||||
|
|
||||||
|
// Starts listening connection on given address and port and serves
|
||||||
|
// incoming requests in SSL/TLS encrypted connection.
|
||||||
|
boost::system::error_code
|
||||||
|
listen_and_serve(boost::system::error_code &ec,
|
||||||
|
boost::asio::ssl::context &tls_context,
|
||||||
|
const std::string &address, const std::string &port);
|
||||||
|
|
||||||
// Registers request handler |cb| with path pattern |pattern|. This
|
// Registers request handler |cb| with path pattern |pattern|. This
|
||||||
// function will fail and returns false if same pattern has been
|
// function will fail and returns false if same pattern has been
|
||||||
|
@ -141,10 +150,6 @@ public:
|
||||||
// It defaults to 1.
|
// It defaults to 1.
|
||||||
void num_threads(size_t num_threads);
|
void num_threads(size_t num_threads);
|
||||||
|
|
||||||
// Sets TLS private key file and certificate file. Both files must
|
|
||||||
// be in PEM format.
|
|
||||||
void tls(std::string private_key_file, std::string certificate_file);
|
|
||||||
|
|
||||||
// Sets the maximum length to which the queue of pending
|
// Sets the maximum length to which the queue of pending
|
||||||
// connections.
|
// connections.
|
||||||
void backlog(int backlog);
|
void backlog(int backlog);
|
||||||
|
@ -153,6 +158,13 @@ private:
|
||||||
std::unique_ptr<http2_impl> impl_;
|
std::unique_ptr<http2_impl> impl_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Configures |tls_context| for server use. This function sets couple
|
||||||
|
// of OpenSSL options (disables SSLv2 and SSLv3 and compression) and
|
||||||
|
// enables ECDHE ciphers. NPN callback is also configured.
|
||||||
|
boost::system::error_code
|
||||||
|
configure_tls_context_easy(boost::system::error_code &ec,
|
||||||
|
boost::asio::ssl::context &tls_context);
|
||||||
|
|
||||||
// Returns request handler to do redirect to |uri| using
|
// Returns request handler to do redirect to |uri| using
|
||||||
// |status_code|. The |uri| appears in "location" header field as is.
|
// |status_code|. The |uri| appears in "location" header field as is.
|
||||||
request_cb redirect_handler(int status_code, std::string uri);
|
request_cb redirect_handler(int status_code, std::string uri);
|
||||||
|
|
Loading…
Reference in New Issue