mirror of
https://github.com/boostorg/beast.git
synced 2025-07-30 04:47:29 +02:00
committed by
Mohammad Nejati
parent
0451018f25
commit
41c1abb402
@ -13,4 +13,6 @@ add_subdirectory(advanced)
|
||||
add_subdirectory(http)
|
||||
add_subdirectory(websocket)
|
||||
|
||||
add_subdirectory(doc)
|
||||
|
||||
add_subdirectory(echo-op)
|
||||
|
@ -30,5 +30,7 @@ build-project advanced ;
|
||||
build-project http ;
|
||||
build-project websocket ;
|
||||
|
||||
build-project doc ;
|
||||
|
||||
# legacy
|
||||
build-project echo-op ;
|
||||
|
12
example/doc/CMakeLists.txt
Normal file
12
example/doc/CMakeLists.txt
Normal file
@ -0,0 +1,12 @@
|
||||
#
|
||||
# Copyright (c) 2025 Mohammad Nejati
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
#
|
||||
# Official repository: https://github.com/boostorg/beast
|
||||
#
|
||||
|
||||
if (OPENSSL_FOUND)
|
||||
add_subdirectory(ssl)
|
||||
endif ()
|
10
example/doc/Jamfile
Normal file
10
example/doc/Jamfile
Normal file
@ -0,0 +1,10 @@
|
||||
#
|
||||
# Copyright (c) 2025 Mohammad Nejati
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
#
|
||||
# Official repository: https://github.com/boostorg/beast
|
||||
#
|
||||
|
||||
build-project ssl ;
|
44
example/doc/ssl/CMakeLists.txt
Normal file
44
example/doc/ssl/CMakeLists.txt
Normal file
@ -0,0 +1,44 @@
|
||||
#
|
||||
# Copyright (c) 2025 Mohammad Nejati
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
#
|
||||
# Official repository: https://github.com/boostorg/beast
|
||||
#
|
||||
|
||||
# Client
|
||||
add_executable(doc-ssl-client
|
||||
Jamfile
|
||||
client.cpp)
|
||||
|
||||
source_group("" FILES
|
||||
Jamfile
|
||||
client.cpp)
|
||||
|
||||
target_include_directories(doc-ssl-client
|
||||
PRIVATE ${PROJECT_SOURCE_DIR})
|
||||
|
||||
target_link_libraries(doc-ssl-client
|
||||
PRIVATE Boost::beast OpenSSL::SSL OpenSSL::Crypto)
|
||||
|
||||
set_target_properties(doc-ssl-client
|
||||
PROPERTIES FOLDER "example-doc-ssl")
|
||||
|
||||
# Server
|
||||
add_executable(doc-ssl-server
|
||||
Jamfile
|
||||
server.cpp)
|
||||
|
||||
source_group("" FILES
|
||||
Jamfile
|
||||
server.cpp)
|
||||
|
||||
target_include_directories(doc-ssl-server
|
||||
PRIVATE ${PROJECT_SOURCE_DIR})
|
||||
|
||||
target_link_libraries(doc-ssl-server
|
||||
PRIVATE Boost::beast OpenSSL::SSL OpenSSL::Crypto)
|
||||
|
||||
set_target_properties(doc-ssl-server
|
||||
PROPERTIES FOLDER "example-doc-ssl")
|
20
example/doc/ssl/Jamfile
Normal file
20
example/doc/ssl/Jamfile
Normal file
@ -0,0 +1,20 @@
|
||||
import ac ;
|
||||
|
||||
project
|
||||
: requirements
|
||||
[ ac.check-library /boost/beast/test//lib-asio-ssl : <library>/boost/beast/test//lib-asio-ssl/<link>static : <build>no ]
|
||||
;
|
||||
|
||||
exe doc-ssl-client :
|
||||
client.cpp
|
||||
:
|
||||
<variant>coverage:<build>no
|
||||
<variant>ubasan:<build>no
|
||||
;
|
||||
|
||||
exe doc-ssl-server :
|
||||
server.cpp
|
||||
:
|
||||
<variant>coverage:<build>no
|
||||
<variant>ubasan:<build>no
|
||||
;
|
137
example/doc/ssl/client.cpp
Normal file
137
example/doc/ssl/client.cpp
Normal file
@ -0,0 +1,137 @@
|
||||
//
|
||||
// Copyright (c) 2025 Mohammad Nejati
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/beast
|
||||
//
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <boost/beast.hpp>
|
||||
#include <boost/beast/ssl.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#if defined(BOOST_ASIO_HAS_CO_AWAIT)
|
||||
|
||||
namespace beast = boost::beast;
|
||||
namespace http = beast::http;
|
||||
namespace net = boost::asio;
|
||||
namespace ssl = net::ssl;
|
||||
|
||||
void
|
||||
print_exception(std::exception_ptr eptr)
|
||||
{
|
||||
if(eptr)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::rethrow_exception(eptr);
|
||||
}
|
||||
catch(std::exception& e)
|
||||
{
|
||||
std::cerr << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
net::awaitable<void>
|
||||
request(ssl::context& ctx)
|
||||
{
|
||||
auto executor = co_await net::this_coro::executor;
|
||||
net::ip::tcp::endpoint endpoint{ {}, 8080 };
|
||||
ssl::stream<net::ip::tcp::socket> stream{ executor, ctx };
|
||||
|
||||
// Connect TCP socket
|
||||
co_await stream.lowest_layer().async_connect(endpoint);
|
||||
|
||||
// Set Server Name Indication (SNI)
|
||||
if(!SSL_set_tlsext_host_name(stream.native_handle(), "localhost"))
|
||||
{
|
||||
throw beast::system_error(
|
||||
static_cast<int>(::ERR_get_error()),
|
||||
net::error::get_ssl_category());
|
||||
}
|
||||
|
||||
// Set a callback to verify that the hostname in the server
|
||||
// certificate matches the expected value
|
||||
stream.set_verify_callback(ssl::host_name_verification("localhost"));
|
||||
|
||||
// Perform the SSL handshake
|
||||
co_await stream.async_handshake(ssl::stream_base::client);
|
||||
|
||||
// Write an HTTP GET request
|
||||
http::request<http::empty_body> req{ http::verb::get, "/", 11 };
|
||||
req.set(http::field::host, "localhost");
|
||||
req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
|
||||
co_await http::async_write(stream, req);
|
||||
|
||||
// Read the response
|
||||
beast::flat_buffer buf;
|
||||
http::response<http::string_body> res;
|
||||
co_await http::async_read(stream, buf, res);
|
||||
|
||||
// Print the response body
|
||||
std::cout << res.body();
|
||||
|
||||
// Gracefully shutdown the SSL stream
|
||||
auto [ec] = co_await stream.async_shutdown(net::as_tuple);
|
||||
if(ec && ec != ssl::error::stream_truncated)
|
||||
throw boost::system::system_error(ec);
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
try
|
||||
{
|
||||
// The io_context is required for all I/O
|
||||
net::io_context ioc;
|
||||
|
||||
// The SSL context is required, and holds certificates,
|
||||
// configurations and session related data
|
||||
ssl::context ctx{ ssl::context::sslv23 };
|
||||
|
||||
// https://docs.openssl.org/3.4/man3/SSL_CTX_set_options/
|
||||
ctx.set_options(
|
||||
ssl::context::no_sslv2 | ssl::context::default_workarounds |
|
||||
ssl::context::single_dh_use);
|
||||
|
||||
// set up the peer verification mode so that the TLS/SSL handshake fails
|
||||
// if the certificate verification is unsuccessful
|
||||
ctx.set_verify_mode(ssl::verify_peer);
|
||||
|
||||
// The servers's certificate will be verified against this
|
||||
// certificate authority.
|
||||
ctx.load_verify_file("ca.crt");
|
||||
|
||||
// In a real application, the passphrase would be read from
|
||||
// a secure place, such as a key vault.
|
||||
ctx.set_password_callback([](auto, auto) { return "123456"; });
|
||||
|
||||
// Client certificate and private key (if server request for).
|
||||
ctx.use_certificate_chain_file("client.crt");
|
||||
ctx.use_private_key_file("client.key", ssl::context::pem);
|
||||
|
||||
net::co_spawn(ioc, request(ctx), print_exception);
|
||||
|
||||
ioc.run();
|
||||
}
|
||||
catch(std::exception& e)
|
||||
{
|
||||
std::cerr << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int
|
||||
main(int, char*[])
|
||||
{
|
||||
std::printf("awaitables require C++20\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
#endif
|
133
example/doc/ssl/server.cpp
Normal file
133
example/doc/ssl/server.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
//
|
||||
// Copyright (c) 2025 Mohammad Nejati
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/beast
|
||||
//
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <boost/beast.hpp>
|
||||
#include <boost/beast/ssl.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#if defined(BOOST_ASIO_HAS_CO_AWAIT)
|
||||
|
||||
namespace beast = boost::beast;
|
||||
namespace http = beast::http;
|
||||
namespace net = boost::asio;
|
||||
namespace ssl = net::ssl;
|
||||
|
||||
void
|
||||
print_exception(std::exception_ptr eptr)
|
||||
{
|
||||
if(eptr)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::rethrow_exception(eptr);
|
||||
}
|
||||
catch(std::exception& e)
|
||||
{
|
||||
std::cerr << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
net::awaitable<void>
|
||||
handle_session(ssl::stream<net::ip::tcp::socket> stream)
|
||||
{
|
||||
// Perform the SSL handshake
|
||||
co_await stream.async_handshake(ssl::stream_base::server);
|
||||
|
||||
// Read and discard a request
|
||||
beast::flat_buffer buf;
|
||||
http::request<http::empty_body> req;
|
||||
co_await http::async_read(stream, buf, req);
|
||||
|
||||
// Write the response
|
||||
http::response<http::string_body> res;
|
||||
res.body() = "Hello!";
|
||||
co_await http::async_write(stream, res);
|
||||
|
||||
// Gracefully shutdown the SSL stream
|
||||
auto [ec] = co_await stream.async_shutdown(net::as_tuple);
|
||||
if(ec && ec != ssl::error::stream_truncated)
|
||||
throw boost::system::system_error(ec);
|
||||
}
|
||||
|
||||
net::awaitable<void>
|
||||
acceptor(ssl::context& ctx)
|
||||
{
|
||||
auto executor = co_await net::this_coro::executor;
|
||||
net::ip::tcp::endpoint endpoint{ {}, 8080 };
|
||||
net::ip::tcp::acceptor acceptor{ executor, endpoint };
|
||||
|
||||
for(;;)
|
||||
{
|
||||
net::co_spawn(
|
||||
executor,
|
||||
handle_session({ co_await acceptor.async_accept(), ctx }),
|
||||
print_exception);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
try
|
||||
{
|
||||
// The io_context is required for all I/O
|
||||
net::io_context ioc;
|
||||
|
||||
// The SSL context is required, and holds certificates,
|
||||
// configurations and session related data
|
||||
ssl::context ctx{ ssl::context::sslv23 };
|
||||
|
||||
// https://docs.openssl.org/3.4/man3/SSL_CTX_set_options/
|
||||
ctx.set_options(
|
||||
ssl::context::no_sslv2 | ssl::context::default_workarounds |
|
||||
ssl::context::single_dh_use);
|
||||
|
||||
// Comment this line to disable client certificate request.
|
||||
ctx.set_verify_mode(
|
||||
ssl::verify_peer | ssl::verify_fail_if_no_peer_cert);
|
||||
|
||||
// The client's certificate will be verified against this
|
||||
// certificate authority.
|
||||
ctx.load_verify_file("ca.crt");
|
||||
|
||||
// In a real application, the passphrase would be read from
|
||||
// a secure place, such as a key vault.
|
||||
ctx.set_password_callback([](auto, auto) { return "123456"; });
|
||||
|
||||
// Server certificate and private key.
|
||||
ctx.use_certificate_chain_file("server.crt");
|
||||
ctx.use_private_key_file("server.key", ssl::context::pem);
|
||||
|
||||
// DH parameters for DHE-based cipher suites
|
||||
ctx.use_tmp_dh_file("dh4096.pem");
|
||||
|
||||
net::co_spawn(ioc, acceptor(ctx), print_exception);
|
||||
|
||||
ioc.run();
|
||||
}
|
||||
catch(std::exception& e)
|
||||
{
|
||||
std::cerr << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int
|
||||
main(int, char*[])
|
||||
{
|
||||
std::printf("awaitables require C++20\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user