Bug #11302 » w20230310b_TEST_11302-avoid-use-after-free-with-closed-listeners.patch
| examples/blog/blog.C | ||
|---|---|---|
|
std::unique_ptr<Wt::Dbo::SqlConnectionPool> blogDb
|
||
|
= BlogSession::createConnectionPool(server.appRoot() + "blog.db");
|
||
|
BlogRSSFeed rssFeed(*blogDb, "Wt blog example", "", "It's just an example.");
|
||
|
auto rssFeed = std::make_shared<BlogRSSFeed>(*blogDb, "Wt blog example", "", "It's just an example.");
|
||
|
server.addResource(&rssFeed, FeedUrl);
|
||
|
server.addResource(rssFeed, FeedUrl);
|
||
|
//When the blog application is deployed in ISAPI on the path "/blog"
|
||
|
//the resources (css+images) are not fetched correctly
|
||
|
server.addEntryPoint(Wt::EntryPointType::Application,
|
||
| examples/feature/oidc/Oidc.C | ||
|---|---|---|
|
});
|
||
|
Session tokenSession(dbPath);
|
||
|
Wt::Auth::OAuthTokenEndpoint tokenEndpoint{tokenSession.users(), deployUrl};
|
||
|
server.addResource(&tokenEndpoint, "/oauth2/token");
|
||
|
auto tokenEndpoint = std::make_shared<Wt::Auth::OAuthTokenEndpoint>(tokenSession.users(), deployUrl);
|
||
|
server.addResource(tokenEndpoint, "/oauth2/token");
|
||
|
Session userInfoSession(dbPath);
|
||
|
Wt::Auth::OidcUserInfoEndpoint userInfoEndpoint{userInfoSession.users()};
|
||
|
server.addResource(&userInfoEndpoint, "/oidc/userinfo");
|
||
|
auto userInfoEndpoint = std::make_shared<Wt::Auth::OidcUserInfoEndpoint>(userInfoSession.users());
|
||
|
server.addResource(userInfoEndpoint, "/oidc/userinfo");
|
||
|
Session::configureAuth();
|
||
| examples/feature/urlparams/urlparams.C | ||
|---|---|---|
|
int main(int argc, char *argv[])
|
||
|
{
|
||
|
Resource resource;
|
||
|
try {
|
||
|
Wt::WServer server{argc, argv, WTHTTP_CONFIGURATION};
|
||
|
server.addResource(&resource, "/users");
|
||
|
server.addResource(&resource, "/users/${user}");
|
||
|
server.addResource(&resource, "/users/${user}/posts");
|
||
|
server.addResource(&resource, "/users/${user}/posts/${post}");
|
||
|
auto resource = std::make_shared<Resource>();
|
||
|
server.addResource(resource, "/users");
|
||
|
server.addResource(resource, "/users/${user}");
|
||
|
server.addResource(resource, "/users/${user}/posts");
|
||
|
server.addResource(resource, "/users/${user}/posts/${post}");
|
||
|
server.run();
|
||
|
} catch (const Wt::WServer::Exception &e) {
|
||
| examples/te-benchmark/benchmark.cpp | ||
|---|---|---|
|
bundle->use(server.appRoot() + "fortunes");
|
||
|
server.setLocalizedStrings(bundle);
|
||
|
JsonResource jsonResource;
|
||
|
server.addResource(&jsonResource, "/json");
|
||
|
server.addResource(std::make_shared<JsonResource>(), "/json");
|
||
|
DbResource dbResource;
|
||
|
server.addResource(&dbResource, "/db");
|
||
|
server.addResource(std::make_shared<DbResource>(), "/db");
|
||
|
QueriesResource queriesResource;
|
||
|
server.addResource(&queriesResource, "/queries");
|
||
|
server.addResource(std::make_shared<QueriesResource>(), "/queries");
|
||
|
FortuneResource fortuneResource;
|
||
|
server.addResource(&fortuneResource, "/fortune");
|
||
|
server.addResource(std::make_shared<FortuneResource>(), "/fortune");
|
||
|
UpdateResource updateResource;
|
||
|
server.addResource(&updateResource, "/updates");
|
||
|
server.addResource(std::make_shared<UpdateResource>(), "/updates");
|
||
|
PlaintextResource plaintextResource;
|
||
|
server.addResource(&plaintextResource, "/plaintext");
|
||
|
server.addResource(std::make_shared<PlaintextResource>(), "/plaintext");
|
||
|
if (server.start()) {
|
||
|
int sig = Wt::WServer::waitForShutdown();
|
||
| examples/wt-homepage/main.C | ||
|---|---|---|
|
std::unique_ptr<Dbo::SqlConnectionPool> blogDb
|
||
|
= BlogSession::createConnectionPool(server.appRoot() + "blog.db");
|
||
|
BlogRSSFeed rssFeed(*blogDb, "Wt and JWt blog",
|
||
|
"http://www.webtoolkit.eu/wt/blog",
|
||
|
"We care about our webtoolkits.");
|
||
|
auto rssFeed = std::make_shared<BlogRSSFeed>(*blogDb,
|
||
|
"Wt and JWt blog",
|
||
|
"http://www.webtoolkit.eu/wt/blog",
|
||
|
"We care about our webtoolkits.");
|
||
|
server.addResource(&rssFeed, "/wt/blog/feed/");
|
||
|
server.addResource(rssFeed, "/wt/blog/feed/");
|
||
|
server.addEntryPoint(EntryPointType::Application,
|
||
|
std::bind(&createJWtHomeApplication, std::placeholders::_1, blogDb.get()),
|
||
| src/Wt/Auth/OAuthService.C | ||
|---|---|---|
|
#include "WebSession.h"
|
||
|
#include "WebRequest.h"
|
||
|
#include <memory>
|
||
|
#ifdef WT_THREADED
|
||
|
#include <mutex>
|
||
|
#endif // WT_THREADED
|
||
| ... | ... | |
|
const OAuthService& service_;
|
||
|
};
|
||
|
std::unique_ptr<RedirectEndpoint> redirectResource_;
|
||
|
std::shared_ptr<RedirectEndpoint> redirectResource_;
|
||
|
std::string secret_;
|
||
|
};
|
||
| ... | ... | |
|
std::unique_lock<std::mutex> guard(impl_->mutex_);
|
||
|
#endif
|
||
|
if (!impl_->redirectResource_) {
|
||
|
auto r = std::unique_ptr<Impl::RedirectEndpoint>(new Impl::RedirectEndpoint(*this));
|
||
|
auto r = std::make_shared<Impl::RedirectEndpoint>(*this);
|
||
|
std::string path = redirectEndpointPath();
|
||
|
LOG_INFO("deploying endpoint at " << path);
|
||
| ... | ... | |
|
else
|
||
|
server = WServer::instance();
|
||
|
server->addResource(r.get(), path);
|
||
|
server->addResource(r, path);
|
||
|
impl_->redirectResource_ = std::move(r);
|
||
|
impl_->redirectResource_ = r;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
| src/Wt/Auth/Saml/Service.C | ||
|---|---|---|
|
void Service::generateAcsEndpoint()
|
||
|
{
|
||
|
auto resource = std::make_unique<StaticAcsResource>(*this);
|
||
|
auto resource = std::make_shared<StaticAcsResource>(*this);
|
||
|
std::string path = acsPath();
|
||
|
LOG_INFO("deploying endpoint at " << path);
|
||
| ... | ... | |
|
server = WServer::instance();
|
||
|
}
|
||
|
server->addResource(resource.get(), path);
|
||
|
staticAcsResource_ = std::move(resource);
|
||
|
server->addResource(resource, path);
|
||
|
}
|
||
|
void Service::generateMetadataEndpoint()
|
||
| ... | ... | |
|
if (metadataPath_.empty())
|
||
|
return;
|
||
|
metadataResource_ = std::make_unique<MetadataResource>(*this);
|
||
|
auto resource = std::make_shared<MetadataResource>(*this);
|
||
|
WApplication *app = WApplication::instance();
|
||
|
WServer *server = nullptr;
|
||
|
if (app) {
|
||
| ... | ... | |
|
server = WServer::instance();
|
||
|
}
|
||
|
server->addResource(metadataResource_.get(), metadataPath_);
|
||
|
server->addResource(resource, metadataPath_);
|
||
|
}
|
||
|
std::string Service::metadata() const
|
||
| src/Wt/Auth/Saml/Service.h | ||
|---|---|---|
|
// state
|
||
|
std::unique_ptr<ServiceImpl> impl_;
|
||
|
std::unique_ptr<StaticAcsResource> staticAcsResource_;
|
||
|
std::unique_ptr<MetadataResource> metadataResource_;
|
||
|
// configuration
|
||
|
std::string secret_;
|
||
| src/Wt/WServer.C | ||
|---|---|---|
|
}
|
||
|
}
|
||
|
void WServer::addResource(const std::shared_ptr<WResource> &resource,
|
||
|
const std::string &path)
|
||
|
{
|
||
|
bool success = configuration().tryAddResource(EntryPoint(resource, prependDefaultPath(path)));
|
||
|
if (success) {
|
||
|
resource->setInternalPath(path);
|
||
|
} else {
|
||
|
WString error(Wt::utf8("WServer::addResource() error: "
|
||
|
"a static resource was already deployed on path '{1}'"));
|
||
|
throw WServer::Exception(error.arg(path).toUTF8());
|
||
|
}
|
||
|
}
|
||
|
void WServer::removeEntryPoint(const std::string& path){
|
||
|
configuration().removeEntryPoint(path);
|
||
|
}
|
||
| src/Wt/WServer.h | ||
|---|---|---|
|
* public. Use this method to add a public resource with a fixed
|
||
|
* path.
|
||
|
*
|
||
|
* \throw Exception if an entrypoint was already registered at the given path
|
||
|
*
|
||
|
* \sa removeEntryPoint()
|
||
|
*/
|
||
|
WT_API void addResource(const std::shared_ptr<WResource>& resource, const std::string& path);
|
||
|
/*! \brief Binds a resource to a fixed path.
|
||
|
*
|
||
|
* Resources may either be private to a single session or
|
||
|
* public. Use this method to add a public resource with a fixed
|
||
|
* path.
|
||
|
*
|
||
|
* \note Ownership of the resource is external to %WServer. The resource first needs
|
||
|
* to be \link removeEntryPoint() removed\endlink (while the server is
|
||
|
* \link stop() stopped\endlink) before being destroyed, or has to outlive the %WServer.
|
||
|
*
|
||
|
* \throw Exception if an entrypoint was already registered at the given path
|
||
|
*
|
||
|
* \sa removeEntryPoint()
|
||
|
*
|
||
|
* \deprecated Use addResource(const std::shared_ptr<WResource>&, const std::string&) instead.
|
||
|
*/
|
||
|
WT_DEPRECATED("Use addResource(const std::shared_ptr<WResource>&, const std::string&) instead")
|
||
|
WT_API void addResource(WResource *resource, const std::string& path);
|
||
|
/*! \brief Removes an entry point.
|
||
| src/web/EntryPoint.C | ||
|---|---|---|
|
path_(path)
|
||
|
{ }
|
||
|
EntryPoint::EntryPoint(const std::shared_ptr<WResource>& resource, const std::string& path)
|
||
|
: type_(EntryPointType::StaticResource),
|
||
|
resource_(resource.get()),
|
||
|
ownedResource_(resource),
|
||
|
appCallback_(nullptr),
|
||
|
path_(path)
|
||
|
{ }
|
||
|
EntryPoint::~EntryPoint()
|
||
|
{
|
||
|
}
|
||
| src/web/EntryPoint.h | ||
|---|---|---|
|
const std::string& path,
|
||
|
const std::string& favicon);
|
||
|
EntryPoint(WResource *resource, const std::string& path);
|
||
|
EntryPoint(const std::shared_ptr<WResource>& resource, const std::string& path);
|
||
|
~EntryPoint();
|
||
|
void setPath(const std::string& path);
|
||
| ... | ... | |
|
private:
|
||
|
EntryPointType type_;
|
||
|
WResource *resource_;
|
||
|
std::shared_ptr<WResource> ownedResource_;
|
||
|
ApplicationCreator appCallback_;
|
||
|
std::string path_;
|
||
|
std::string favicon_;
|
||
| test/http/HttpClientServerTest.C | ||
|---|---|---|
|
"--docroot", "."
|
||
|
};
|
||
|
setServerConfiguration(argc, (char **)argv);
|
||
|
addResource(&resource_, "/test");
|
||
|
resource_ = std::make_shared<TestResource>();
|
||
|
addResource(resource_, "/test");
|
||
|
}
|
||
|
std::string address()
|
||
| ... | ... | |
|
return "127.0.0.1:" + std::to_string(httpPort());
|
||
|
}
|
||
|
TestResource& resource() { return resource_; }
|
||
|
TestResource& resource() { return *resource_; }
|
||
|
private:
|
||
|
TestResource resource_;
|
||
|
std::shared_ptr<TestResource> resource_;
|
||
|
};
|
||
|
class Client : public Wt::WObject {
|
||
|
-
|
||
| src/http/Server.C | ||
|---|---|---|
|
const std::string &address,
|
||
|
Wt::AsioWrapper::error_code &errc)
|
||
|
{
|
||
|
tcp_listeners_.push_back(TcpListener(asio::ip::tcp::acceptor(wt_.ioService()), TcpConnectionPtr()));
|
||
|
asio::ip::tcp::acceptor &tcp_acceptor = tcp_listeners_.back().acceptor;
|
||
|
tcp_listeners_.push_back(std::make_shared<TcpListener>(asio::ip::tcp::acceptor(wt_.ioService()), TcpConnectionPtr()));
|
||
|
asio::ip::tcp::acceptor &tcp_acceptor = tcp_listeners_.back()->acceptor;
|
||
|
tcp_acceptor.open(endpoint.protocol());
|
||
|
tcp_acceptor.set_option(asio::ip::tcp::acceptor::reuse_address(true));
|
||
|
#ifndef WT_WIN32
|
||
| ... | ... | |
|
LOG_INFO_S(&wt_, "started server: " << addressString("http", endpoint, address));
|
||
|
tcp_listeners_.back().new_connection.reset
|
||
|
tcp_listeners_.back()->new_connection.reset
|
||
|
(new TcpConnection(wt_.ioService(), this, connection_manager_,
|
||
|
request_handler_));
|
||
|
} else {
|
||
| ... | ... | |
|
const std::string &address,
|
||
|
Wt::AsioWrapper::error_code &errc)
|
||
|
{
|
||
|
ssl_listeners_.push_back(SslListener(asio::ip::tcp::acceptor(wt_.ioService()), SslConnectionPtr()));
|
||
|
asio::ip::tcp::acceptor &ssl_acceptor = ssl_listeners_.back().acceptor;
|
||
|
ssl_listeners_.push_back(std::make_shared<SslListener>(asio::ip::tcp::acceptor(wt_.ioService()), SslConnectionPtr()));
|
||
|
asio::ip::tcp::acceptor &ssl_acceptor = ssl_listeners_.back()->acceptor;
|
||
|
ssl_acceptor.open(endpoint.protocol());
|
||
|
ssl_acceptor.set_option(asio::ip::tcp::acceptor::reuse_address(true));
|
||
|
#ifndef WT_WIN32
|
||
| ... | ... | |
|
LOG_INFO_S(&wt_, "started server: " << addressString("https", endpoint, address));
|
||
|
ssl_listeners_.back().new_connection.reset
|
||
|
ssl_listeners_.back()->new_connection.reset
|
||
|
(new SslConnection(wt_.ioService(), this, ssl_context_, connection_manager_,
|
||
|
request_handler_));
|
||
|
} else {
|
||
| ... | ... | |
|
if (ssl_listeners_.empty())
|
||
|
return -1;
|
||
|
else
|
||
|
return ssl_listeners_.front().acceptor.local_endpoint().port();
|
||
|
return ssl_listeners_.front()->acceptor.local_endpoint().port();
|
||
|
#else // HTTP_WITH_SSL
|
||
|
return -1;
|
||
|
#endif // HTTP_WITH_SSL
|
||
|
}
|
||
|
return tcp_listeners_.front().acceptor.local_endpoint().port();
|
||
|
return tcp_listeners_.front()->acceptor.local_endpoint().port();
|
||
|
}
|
||
|
void Server::startAccept()
|
||
| ... | ... | |
|
* need to access the ConnectionManager mutex in any case).
|
||
|
*/
|
||
|
for (std::size_t i = 0; i < tcp_listeners_.size(); ++i) {
|
||
|
asio::ip::tcp::acceptor &acceptor = tcp_listeners_[i].acceptor;
|
||
|
TcpConnectionPtr &new_connection = tcp_listeners_[i].new_connection;
|
||
|
asio::ip::tcp::acceptor &acceptor = tcp_listeners_[i]->acceptor;
|
||
|
TcpConnectionPtr &new_connection = tcp_listeners_[i]->new_connection;
|
||
|
acceptor.async_accept(new_connection->socket(),
|
||
|
accept_strand_.wrap(
|
||
|
std::bind(&Server::handleTcpAccept, this,
|
||
|
&tcp_listeners_[i],
|
||
|
tcp_listeners_[i],
|
||
|
std::placeholders::_1)));
|
||
|
}
|
||
|
#ifdef HTTP_WITH_SSL
|
||
|
for (std::size_t i = 0; i < ssl_listeners_.size(); ++i) {
|
||
|
asio::ip::tcp::acceptor &acceptor = ssl_listeners_[i].acceptor;
|
||
|
SslConnectionPtr &new_connection = ssl_listeners_[i].new_connection;
|
||
|
asio::ip::tcp::acceptor &acceptor = ssl_listeners_[i]->acceptor;
|
||
|
SslConnectionPtr &new_connection = ssl_listeners_[i]->new_connection;
|
||
|
acceptor.async_accept(new_connection->socket(),
|
||
|
accept_strand_.wrap(
|
||
|
std::bind(&Server::handleSslAccept, this,
|
||
|
&ssl_listeners_[i],
|
||
|
ssl_listeners_[i],
|
||
|
std::placeholders::_1)));
|
||
|
}
|
||
|
#endif // HTTP_WITH_SSL
|
||
| ... | ... | |
|
if (!err) {
|
||
|
// tcp_listeners_.front() should be fine here:
|
||
|
// it should be the only acceptor when this is a session process
|
||
|
auto port = tcp_listeners_.front().acceptor.local_endpoint().port();
|
||
|
auto port = tcp_listeners_.front()->acceptor.local_endpoint().port();
|
||
|
Wt::WStringStream ss;
|
||
|
ss << "port:" << port << "\n";
|
||
|
auto buf = std::make_shared<std::string>(ss.str());
|
||
| ... | ... | |
|
void Server::handleResume()
|
||
|
{
|
||
|
for (std::size_t i = 0; i < tcp_listeners_.size(); ++i)
|
||
|
tcp_listeners_[i].acceptor.close();
|
||
|
tcp_listeners_[i]->acceptor.close();
|
||
|
tcp_listeners_.clear();
|
||
|
#ifdef HTTP_WITH_SSL
|
||
|
for (std::size_t i = 0; i < ssl_listeners_.size(); ++i)
|
||
|
ssl_listeners_[i].acceptor.close();
|
||
|
ssl_listeners_[i]->acceptor.close();
|
||
|
ssl_listeners_.clear();
|
||
|
#endif // HTTP_WITH_SSL
|
||
|
start();
|
||
|
}
|
||
|
void Server::handleTcpAccept(TcpListener *listener, const Wt::AsioWrapper::error_code& e)
|
||
|
void Server::handleTcpAccept(const std::weak_ptr<TcpListener>& listener,
|
||
|
const Wt::AsioWrapper::error_code& e)
|
||
|
{
|
||
|
if (!e) {
|
||
|
connection_manager_.start(listener->new_connection);
|
||
|
listener->new_connection.reset(new TcpConnection(wt_.ioService(), this,
|
||
|
connection_manager_, request_handler_));
|
||
|
} else if (!listener->acceptor.is_open()) {
|
||
|
auto l = listener.lock();
|
||
|
if (!l || (e && !l->acceptor.is_open())) {
|
||
|
// server shutdown
|
||
|
LOG_DEBUG("handleTcpAccept: async_accept error (acceptor closed, probably server shutdown): " << e.message());
|
||
|
LOG_DEBUG("handleTcpAccept: async_accept error (no listener, probably server shutdown): " << e.message());
|
||
|
return;
|
||
|
}
|
||
|
if (!e) {
|
||
|
connection_manager_.start(l->new_connection);
|
||
|
l->new_connection.reset(new TcpConnection(wt_.ioService(), this,
|
||
|
connection_manager_, request_handler_));
|
||
|
} else {
|
||
|
LOG_ERROR("handleTcpAccept: async_accept error: " << e.message());
|
||
|
}
|
||
|
listener->acceptor.async_accept(listener->new_connection->socket(),
|
||
|
accept_strand_.wrap(
|
||
|
std::bind(&Server::handleTcpAccept, this,
|
||
|
listener, std::placeholders::_1)));
|
||
|
l->acceptor.async_accept(l->new_connection->socket(),
|
||
|
accept_strand_.wrap(
|
||
|
std::bind(&Server::handleTcpAccept, this,
|
||
|
listener, std::placeholders::_1)));
|
||
|
}
|
||
|
#ifdef HTTP_WITH_SSL
|
||
|
void Server::handleSslAccept(SslListener *listener, const Wt::AsioWrapper::error_code& e)
|
||
|
void Server::handleSslAccept(const std::weak_ptr<SslListener>& listener,
|
||
|
const Wt::AsioWrapper::error_code& e)
|
||
|
{
|
||
|
if (!e) {
|
||
|
connection_manager_.start(listener->new_connection);
|
||
|
listener->new_connection.reset(new SslConnection(wt_.ioService(), this,
|
||
|
ssl_context_, connection_manager_, request_handler_));
|
||
|
} else if (!listener->acceptor.is_open()) {
|
||
|
auto l = listener.lock();
|
||
|
if (!l || (e && !l->acceptor.is_open())) {
|
||
|
// server shutdown
|
||
|
LOG_DEBUG("handleSslAccept: async_accept error (acceptor closed, probably server shutdown): " << e.message());
|
||
|
LOG_DEBUG("handleSslAccept: async_accept error (no listener, probably server shutdown): " << e.message());
|
||
|
return;
|
||
|
}
|
||
|
if (!e) {
|
||
|
connection_manager_.start(l->new_connection);
|
||
|
l->new_connection.reset(new SslConnection(wt_.ioService(), this,
|
||
|
ssl_context_, connection_manager_, request_handler_));
|
||
|
} else {
|
||
|
LOG_ERROR("handleSslAccept: async_accept error: " << e.message());
|
||
|
}
|
||
|
listener->acceptor.async_accept(listener->new_connection->socket(),
|
||
|
accept_strand_.wrap(
|
||
|
std::bind(&Server::handleSslAccept, this,
|
||
|
listener, std::placeholders::_1)));
|
||
|
l->acceptor.async_accept(l->new_connection->socket(),
|
||
|
accept_strand_.wrap(
|
||
|
std::bind(&Server::handleSslAccept, this,
|
||
|
listener, std::placeholders::_1)));
|
||
|
}
|
||
|
#endif // HTTP_WITH_SSL
|
||
| ... | ... | |
|
// operations. Once all operations have finished the io_service::run() call
|
||
|
// will exit.
|
||
|
for (std::size_t i = 0; i < tcp_listeners_.size(); ++i)
|
||
|
tcp_listeners_[i].acceptor.close();
|
||
|
tcp_listeners_[i]->acceptor.close();
|
||
|
tcp_listeners_.clear();
|
||
|
#ifdef HTTP_WITH_SSL
|
||
|
for (std::size_t i = 0; i < ssl_listeners_.size(); ++i)
|
||
|
ssl_listeners_[i].acceptor.close();
|
||
|
ssl_listeners_[i]->acceptor.close();
|
||
|
ssl_listeners_.clear();
|
||
|
#endif // HTTP_WITH_SSL
|
||
| src/http/Server.h | ||
|---|---|---|
|
#include "Wt/WLogger.h"
|
||
|
#include <memory>
|
||
|
namespace http {
|
||
|
namespace server {
|
||
| ... | ... | |
|
void closeParentConnection();
|
||
|
/// Handle completion of an asynchronous accept operation.
|
||
|
void handleTcpAccept(TcpListener *listener, const Wt::AsioWrapper::error_code& e);
|
||
|
void handleTcpAccept(const std::weak_ptr<TcpListener>& listener,
|
||
|
const Wt::AsioWrapper::error_code& e);
|
||
|
/// Handle a request to stop the server.
|
||
|
void handleStop();
|
||
| ... | ... | |
|
Wt::AsioWrapper::strand accept_strand_;
|
||
|
/// Acceptors used to listen for incoming http connections.
|
||
|
std::vector<TcpListener> tcp_listeners_;
|
||
|
std::vector<std::shared_ptr<TcpListener>> tcp_listeners_;
|
||
|
#ifdef HTTP_WITH_SSL
|
||
|
struct SslListener {
|
||
| ... | ... | |
|
asio::ssl::context ssl_context_;
|
||
|
/// Acceptors used to listen for incoming https connections
|
||
|
std::vector<SslListener> ssl_listeners_;
|
||
|
std::vector<std::shared_ptr<SslListener>> ssl_listeners_;
|
||
|
/// Add new SSL listener, called from start()
|
||
|
void addSslListener(asio::ip::tcp::resolver &resolver,
|
||
| ... | ... | |
|
Wt::AsioWrapper::error_code &errc);
|
||
|
/// Handle completion of an asynchronous SSL accept operation.
|
||
|
void handleSslAccept(SslListener *listener, const Wt::AsioWrapper::error_code& e);
|
||
|
void handleSslAccept(const std::weak_ptr<SslListener>& listener,
|
||
|
const Wt::AsioWrapper::error_code& e);
|
||
|
#endif // HTTP_WITH_SSL
|
||
|
void handleTimeout(asio::steady_timer *timer,
|
||
|
-
|
||
| test/http/HttpClientServerTest.C | ||
|---|---|---|
|
Exception,
|
||
|
};
|
||
|
constexpr auto SimulatedWorkTime = std::chrono::milliseconds{500};
|
||
|
class TestResource : public WResource
|
||
|
{
|
||
|
public:
|
||
| ... | ... | |
|
: delaySendingBody_(false),
|
||
|
haveEverMoreData_(false),
|
||
|
haveRandomMoreData_(false),
|
||
|
simulateWork_(false),
|
||
|
aborted_(0)
|
||
|
{ }
|
||
| ... | ... | |
|
return aborted_;
|
||
|
}
|
||
|
void simulateWork() {
|
||
|
simulateWork_ = true;
|
||
|
}
|
||
|
virtual void handleRequest(const Http::Request& request,
|
||
|
Http::Response& response) override
|
||
|
{
|
||
|
if (simulateWork_)
|
||
|
std::this_thread::sleep_for(SimulatedWorkTime);
|
||
|
switch (type_) {
|
||
|
case TestType::Simple:
|
||
|
return handleSimple(request, response);
|
||
| ... | ... | |
|
bool delaySendingBody_;
|
||
|
bool haveEverMoreData_;
|
||
|
bool haveRandomMoreData_;
|
||
|
bool simulateWork_;
|
||
|
int aborted_;
|
||
|
TestType type_ = TestType::Simple;
|
||
| ... | ... | |
|
}
|
||
|
}
|
||
|
BOOST_AUTO_TEST_CASE( http_client_server_clean_shutdown )
|
||
|
{
|
||
|
Server server;
|
||
|
server.resource().setType(TestType::Continuation);
|
||
|
server.resource().simulateWork();
|
||
|
if (server.start()) {
|
||
|
Client client;
|
||
|
client.get("http://" + server.address() + "/test");
|
||
|
std::this_thread::sleep_for(SimulatedWorkTime / 2);
|
||
|
client.abort();
|
||
|
client.waitDone();
|
||
|
}
|
||
|
}
|
||
|
#endif // WT_THREADED
|
||
|
-
|
||
| test/http/HttpClientServerTest.C | ||
|---|---|---|
|
}
|
||
|
}
|
||
|
BOOST_AUTO_TEST_CASE( http_server_clean_close )
|
||
|
{
|
||
|
constexpr unsigned ClientCount {1000};
|
||
|
Server server;
|
||
|
server.resource().setType(TestType::Continuation);
|
||
|
server.resource().simulateWork();
|
||
|
if (server.start()) {
|
||
|
Client client;
|
||
|
std::vector<Client *> clients;
|
||
|
for (unsigned i = 0; i < ClientCount; ++i) {
|
||
|
Client *client = new Client();
|
||
|
client->get("http://" + server.address() + "/test");
|
||
|
clients.push_back(client);
|
||
|
}
|
||
|
server.stop();
|
||
|
for (unsigned i = 0; i < ClientCount; ++i) {
|
||
|
clients[i]->waitDone();
|
||
|
delete clients[i];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif // WT_THREADED
|
||
|
-
|
||
| test/http/HttpClientServerTest.C | ||
|---|---|---|
|
BOOST_AUTO_TEST_CASE( http_server_clean_close )
|
||
|
{
|
||
|
constexpr unsigned ClientCount {1000};
|
||
|
constexpr unsigned ClientCount {500};
|
||
|
Server server;
|
||
|
server.resource().setType(TestType::Continuation);
|
||
| ... | ... | |
|
clients.push_back(client);
|
||
|
}
|
||
|
server.stop();
|
||
|
for (unsigned i = 0; i < ClientCount; ++i) {
|
||
|
if (i == 10)
|
||
|
server.stop();
|
||
|
clients[i]->waitDone();
|
||
|
delete clients[i];
|
||
|
}
|
||