Index: http/Configuration.C =================================================================== --- http/Configuration.C (revision 5) +++ http/Configuration.C (working copy) @@ -49,6 +49,7 @@ configPath_(), httpPort_("80"), httpsPort_("443"), + useSslCallbackProvide_(false), sslCertificateChainFile_(), sslPrivateKeyFile_(), sslTmpDHFile_(), @@ -158,6 +159,9 @@ ("https-port", po::value(&httpsPort_)->default_value(httpsPort_), "HTTPS port (e.g. 443)") + ("use-ssl-callback-provide", + po::value(&useSslCallbackProvide_)->default_value(useSslCallbackProvide_), + "SSL server uses a callback function to provide certificate as X509 object and private key as EVP_PKEY object") ("ssl-certificate", po::value()->default_value(sslCertificateChainFile_), "SSL server certificate chain file\n" @@ -314,11 +318,16 @@ if (vm.count("https-address")) { httpsAddress_ = vm["https-address"].as(); + useSslCallbackProvide_ = vm["use-ssl-callback-provide"].as(); - checkPath(vm, "ssl-certificate", "SSL Certificate chain file", - sslCertificateChainFile_, RegularFile); - checkPath(vm, "ssl-private-key", "SSL Private key file", - sslPrivateKeyFile_, RegularFile | Private); + if(!useSslCallbackProvide_) + { + checkPath(vm, "ssl-certificate", "SSL Certificate chain file", + sslCertificateChainFile_, RegularFile); + checkPath(vm, "ssl-private-key", "SSL Private key file", + sslPrivateKeyFile_, RegularFile | Private); + } + checkPath(vm, "ssl-tmp-dh", "SSL Temporary Diffie-Hellman file", sslTmpDHFile_, RegularFile); } Index: http/Configuration.h =================================================================== --- http/Configuration.h (revision 5) +++ http/Configuration.h (working copy) @@ -24,6 +24,11 @@ } } +struct x509_st; +typedef struct x509_st X509; +struct evp_pkey_st; +typedef struct evp_pkey_st EVP_PKEY; + namespace Wt { class WLogger; class WLogEntry; @@ -36,6 +41,7 @@ { public: typedef boost::function ssl_password_cb_t; + typedef boost::function ssl_provide_cb_t; public: Configuration(Wt::WLogger& logger, bool silent = false); @@ -62,6 +68,7 @@ const std::string& httpsAddress() const { return httpsAddress_; } const std::string& httpsPort() const { return httpsPort_; } + bool hasSslCallbackProvide() const { return useSslCallbackProvide_; } const std::string& sslCertificateChainFile() const { return sslCertificateChainFile_; } const std::string& sslPrivateKeyFile() const { return sslPrivateKeyFile_; } @@ -87,6 +94,12 @@ bool hasSslPasswordCallback() { return sslPasswordCallback_; } + void setSslProvideCallback(ssl_provide_cb_t cb) + { sslProvideCallback_ = cb; } + ssl_provide_cb_t sslProvideCallback() + { return sslProvideCallback_; } + + private: Wt::WLogger& logger_; bool silent_; @@ -108,6 +121,8 @@ std::string httpsAddress_; std::string httpsPort_; + bool useSslCallbackProvide_; + ssl_provide_cb_t sslProvideCallback_; std::string sslCertificateChainFile_; std::string sslPrivateKeyFile_; std::string sslTmpDHFile_; Index: http/Server.C =================================================================== --- http/Server.C (revision 5) +++ http/Server.C (working copy) @@ -1,338 +1,349 @@ -/* - * Copyright (C) 2008 Emweb bvba, Kessel-Lo, Belgium. - * - * All rights reserved. - */ -// -// server.cpp -// ~~~~~~~~~~ -// -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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) -// - -#include - -#include -#include - -#include "Server.h" -#include "Configuration.h" -#include "WebController.h" - -#include - -#ifdef HTTP_WITH_SSL - -#include - -#endif // HTTP_WITH_SSL - -namespace { - std::string bindError(asio::ip::tcp::endpoint ep, - boost::system::system_error e) { - std::stringstream ss; - ss << "Error occurred when binding to " - << ep.address().to_string() - << ":" - << ep.port() - << std::endl - << e.what(); - return ss.str(); - } - -#ifdef HTTP_WITH_SSL - SSL_CTX *nativeContext(asio::ssl::context& context) - { -#if BOOST_VERSION >= 104700 - return context.native_handle(); -#else //BOOST_VERSION < 104700 - return context.impl(); -#endif //BOOST_VERSION >= 104700 - } -#endif //HTTP_WITH_SSL -} - -namespace Wt { - LOGGER("wthttp"); -} - -namespace http { -namespace server { - -Server::Server(const Configuration& config, Wt::WServer& wtServer) - : config_(config), - wt_(wtServer), - accept_strand_(wt_.ioService()), - // post_strand_(ioService_), - tcp_acceptor_(wt_.ioService()), -#ifdef HTTP_WITH_SSL - ssl_context_(wt_.ioService(), asio::ssl::context::sslv23), - ssl_acceptor_(wt_.ioService()), -#endif // HTTP_WITH_SSL - connection_manager_(), - request_handler_(config, wt_.configuration().entryPoints(), accessLogger_) -{ - if (config.accessLog().empty()) - accessLogger_.setStream(std::cout); - else - accessLogger_.setFile(config.accessLog()); - - accessLogger_.addField("remotehost", false); - accessLogger_.addField("rfc931", false); - accessLogger_.addField("authuser", false); - accessLogger_.addField("date", false); - accessLogger_.addField("request", true); - accessLogger_.addField("status", false); - accessLogger_.addField("bytes", false); - - start(); -} - -asio::io_service& Server::service() -{ - return wt_.ioService(); -} - -Wt::WebController *Server::controller() -{ - return wt_.controller(); -} - -void Server::start() -{ - asio::ip::tcp::resolver resolver(wt_.ioService()); - - // HTTP - if (!config_.httpAddress().empty()) { - std::string httpPort = config_.httpPort(); - - asio::ip::tcp::endpoint tcp_endpoint; - - if (httpPort == "0") - tcp_endpoint.address(asio::ip::address::from_string - (config_.httpAddress())); - else { -#ifndef NO_RESOLVE_ACCEPT_ADDRESS - asio::ip::tcp::resolver::query tcp_query(config_.httpAddress(), - config_.httpPort()); - tcp_endpoint = *resolver.resolve(tcp_query); -#else // !NO_RESOLVE_ACCEPT_ADDRESS - tcp_endpoint.address - (asio::ip::address::from_string(config_.httpAddress())); - tcp_endpoint.port(atoi(httpPort.c_str())); -#endif // NO_RESOLVE_ACCEPT_ADDRESS - } - - tcp_acceptor_.open(tcp_endpoint.protocol()); - tcp_acceptor_.set_option(asio::ip::tcp::acceptor::reuse_address(true)); - try { - tcp_acceptor_.bind(tcp_endpoint); - } catch (boost::system::system_error e) { - LOG_ERROR_S(&wt_, bindError(tcp_endpoint, e)); - throw; - } - tcp_acceptor_.listen(); - - LOG_INFO_S(&wt_, "started server: http://" << - config_.httpAddress() << ":" << this->httpPort()); - - new_tcpconnection_.reset - (new TcpConnection(wt_.ioService(), this, connection_manager_, - request_handler_)); - } - - // HTTPS - if (!config_.httpsAddress().empty()) { -#ifdef HTTP_WITH_SSL - LOG_INFO_S(&wt_, "starting server: https://" << - config_.httpsAddress() << ":" << config_.httpsPort()); - - int sslOptions = asio::ssl::context::default_workarounds - | asio::ssl::context::no_sslv2 - | asio::ssl::context::single_dh_use; - - if (!config_.sslEnableV3()) - sslOptions |= asio::ssl::context::no_sslv3; - - ssl_context_.set_options(sslOptions); - - if (config_.hasSslPasswordCallback()) - ssl_context_.set_password_callback(config_.sslPasswordCallback()); - - if (config_.sslClientVerification() == "none") { - ssl_context_.set_verify_mode(asio::ssl::context::verify_none); - } else if (config_.sslClientVerification() == "optional") { - ssl_context_.set_verify_mode(asio::ssl::context::verify_peer); - ssl_context_.load_verify_file(config_.sslCaCertificates()); - } else { - // assume 'required' - ssl_context_.set_verify_mode(asio::ssl::context::verify_peer | - asio::ssl::context::verify_fail_if_no_peer_cert); - ssl_context_.load_verify_file(config_.sslCaCertificates()); - } - - ssl_context_.use_certificate_chain_file(config_.sslCertificateChainFile()); - ssl_context_.use_private_key_file(config_.sslPrivateKeyFile(), - asio::ssl::context::pem); - ssl_context_.use_tmp_dh_file(config_.sslTmpDHFile()); - - SSL_CTX *native_ctx = nativeContext(ssl_context_); - - if (config_.sslCipherList().size()) { - if (!SSL_CTX_set_cipher_list(native_ctx, config_.sslCipherList().c_str())) { - throw Wt::WServer::Exception( - "failed to select ciphers for cipher list " - + config_.sslCipherList()); - } - } - - std::string sessionId = Wt::WRandom::generateId(SSL_MAX_SSL_SESSION_ID_LENGTH); - SSL_CTX_set_session_id_context(native_ctx, - reinterpret_cast(sessionId.c_str()), sessionId.size()); - - asio::ip::tcp::endpoint ssl_endpoint; -#ifndef NO_RESOLVE_ACCEPT_ADDRESS - asio::ip::tcp::resolver::query ssl_query(config_.httpsAddress(), - config_.httpsPort()); - ssl_endpoint = *resolver.resolve(ssl_query); -#else // !NO_RESOLVE_ACCEPT_ADDRESS - ssl_endpoint.address(asio::ip::address::from_string(config_.httpsAddress())); - ssl_endpoint.port(atoi(httpsPort.c_str())); -#endif // NO_RESOLVE_ACCEPT_ADDRESS - - ssl_acceptor_.open(ssl_endpoint.protocol()); - ssl_acceptor_.set_option(asio::ip::tcp::acceptor::reuse_address(true)); - try { - ssl_acceptor_.bind(ssl_endpoint); - } catch (boost::system::system_error e) { - LOG_ERROR_S(&wt_, bindError(ssl_endpoint, e);) - throw; - } - ssl_acceptor_.listen(); - - new_sslconnection_.reset - (new SslConnection(wt_.ioService(), this, ssl_context_, connection_manager_, - request_handler_)); - -#else // HTTP_WITH_SSL - LOG_ERROR_S(&wt_, "built without support for SSL: " - "cannot start https server."); -#endif // HTTP_WITH_SSL - } - - // Win32 cancels the non-blocking accept when the thread that called - // accept exits. To avoid that this happens when called within the - // WServer context, we post the action of calling accept to one of - // the threads in the threadpool. - wt_.ioService().post(boost::bind(&Server::startAccept, this)); -} - -int Server::httpPort() const -{ - return tcp_acceptor_.local_endpoint().port(); -} - -void Server::startAccept() -{ - /* - * For simplicity, we are using the same accept_strand_ for Tcp - * and Ssl, to prevent the close() from within handleStop() and - * async_accept() methods to be called simultaneously. - * - * While this also prevents simultaneously accepting a new Tcp and - * Ssl connection, this performance impact is negligible (and both - * need to access the ConnectionManager mutex in any case). - */ - if (new_tcpconnection_) { - tcp_acceptor_.async_accept(new_tcpconnection_->socket(), - accept_strand_.wrap( - boost::bind(&Server::handleTcpAccept, this, - asio::placeholders::error))); - } - -#ifdef HTTP_WITH_SSL - if (new_sslconnection_) { - ssl_acceptor_.async_accept(new_sslconnection_->socket(), - accept_strand_.wrap( - boost::bind(&Server::handleSslAccept, this, - asio::placeholders::error))); - } -#endif // HTTP_WITH_SSL -} - -Server::~Server() -{ } - -void Server::stop() -{ - // Post a call to the stop function so that server::stop() is safe - // to call from any thread, and not simultaneously with waiting for - // a new async_accept() call. - wt_.ioService().post(accept_strand_.wrap - (boost::bind(&Server::handleStop, this))); -} - -void Server::resume() -{ - wt_.ioService().post(boost::bind(&Server::handleResume, this)); -} - -void Server::handleResume() -{ - tcp_acceptor_.close(); - -#ifdef HTTP_WITH_SSL - ssl_acceptor_.close(); -#endif // HTTP_WITH_SSL - - start(); -} - -void Server::handleTcpAccept(const asio_error_code& e) -{ - if (!e) { - connection_manager_.start(new_tcpconnection_); - new_tcpconnection_.reset(new TcpConnection(wt_.ioService(), this, - connection_manager_, request_handler_)); - tcp_acceptor_.async_accept(new_tcpconnection_->socket(), - accept_strand_.wrap( - boost::bind(&Server::handleTcpAccept, this, - asio::placeholders::error))); - } -} - -#ifdef HTTP_WITH_SSL -void Server::handleSslAccept(const asio_error_code& e) -{ - if (!e) - { - connection_manager_.start(new_sslconnection_); - new_sslconnection_.reset(new SslConnection(wt_.ioService(), this, - ssl_context_, connection_manager_, request_handler_)); - ssl_acceptor_.async_accept(new_sslconnection_->socket(), - accept_strand_.wrap( - boost::bind(&Server::handleSslAccept, this, - asio::placeholders::error))); - } -} -#endif // HTTP_WITH_SSL - -void Server::handleStop() -{ - // The server is stopped by cancelling all outstanding asynchronous - // operations. Once all operations have finished the io_service::run() call - // will exit. - tcp_acceptor_.close(); - -#ifdef HTTP_WITH_SSL - ssl_acceptor_.close(); -#endif // HTTP_WITH_SSL - - connection_manager_.stopAll(); -} - -} // namespace server -} // namespace http +/* + * Copyright (C) 2008 Emweb bvba, Kessel-Lo, Belgium. + * + * All rights reserved. + */ +// +// server.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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) +// + +#include + +#include +#include + +#include "Server.h" +#include "Configuration.h" +#include "WebController.h" + +#include + +#ifdef HTTP_WITH_SSL + +#include + +#endif // HTTP_WITH_SSL + +namespace { + std::string bindError(asio::ip::tcp::endpoint ep, + boost::system::system_error e) { + std::stringstream ss; + ss << "Error occurred when binding to " + << ep.address().to_string() + << ":" + << ep.port() + << std::endl + << e.what(); + return ss.str(); + } + +#ifdef HTTP_WITH_SSL + SSL_CTX *nativeContext(asio::ssl::context& context) + { +#if BOOST_VERSION >= 104700 + return context.native_handle(); +#else //BOOST_VERSION < 104700 + return context.impl(); +#endif //BOOST_VERSION >= 104700 + } +#endif //HTTP_WITH_SSL +} + +namespace Wt { + LOGGER("wthttp"); +} + +namespace http { +namespace server { + +Server::Server(const Configuration& config, Wt::WServer& wtServer) + : config_(config), + wt_(wtServer), + accept_strand_(wt_.ioService()), + // post_strand_(ioService_), + tcp_acceptor_(wt_.ioService()), +#ifdef HTTP_WITH_SSL + ssl_context_(wt_.ioService(), asio::ssl::context::sslv23), + ssl_acceptor_(wt_.ioService()), +#endif // HTTP_WITH_SSL + connection_manager_(), + request_handler_(config, wt_.configuration().entryPoints(), accessLogger_) +{ + if (config.accessLog().empty()) + accessLogger_.setStream(std::cout); + else + accessLogger_.setFile(config.accessLog()); + + accessLogger_.addField("remotehost", false); + accessLogger_.addField("rfc931", false); + accessLogger_.addField("authuser", false); + accessLogger_.addField("date", false); + accessLogger_.addField("request", true); + accessLogger_.addField("status", false); + accessLogger_.addField("bytes", false); + + start(); +} + +asio::io_service& Server::service() +{ + return wt_.ioService(); +} + +Wt::WebController *Server::controller() +{ + return wt_.controller(); +} + +void Server::start() +{ + asio::ip::tcp::resolver resolver(wt_.ioService()); + + // HTTP + if (!config_.httpAddress().empty()) { + std::string httpPort = config_.httpPort(); + + asio::ip::tcp::endpoint tcp_endpoint; + + if (httpPort == "0") + tcp_endpoint.address(asio::ip::address::from_string + (config_.httpAddress())); + else { +#ifndef NO_RESOLVE_ACCEPT_ADDRESS + asio::ip::tcp::resolver::query tcp_query(config_.httpAddress(), + config_.httpPort()); + tcp_endpoint = *resolver.resolve(tcp_query); +#else // !NO_RESOLVE_ACCEPT_ADDRESS + tcp_endpoint.address + (asio::ip::address::from_string(config_.httpAddress())); + tcp_endpoint.port(atoi(httpPort.c_str())); +#endif // NO_RESOLVE_ACCEPT_ADDRESS + } + + tcp_acceptor_.open(tcp_endpoint.protocol()); + tcp_acceptor_.set_option(asio::ip::tcp::acceptor::reuse_address(true)); + try { + tcp_acceptor_.bind(tcp_endpoint); + } catch (boost::system::system_error e) { + LOG_ERROR_S(&wt_, bindError(tcp_endpoint, e)); + throw; + } + tcp_acceptor_.listen(); + + LOG_INFO_S(&wt_, "started server: http://" << + config_.httpAddress() << ":" << this->httpPort()); + + new_tcpconnection_.reset + (new TcpConnection(wt_.ioService(), this, connection_manager_, + request_handler_)); + } + + // HTTPS + if (!config_.httpsAddress().empty()) { +#ifdef HTTP_WITH_SSL + LOG_INFO_S(&wt_, "starting server: https://" << + config_.httpsAddress() << ":" << config_.httpsPort()); + + int sslOptions = asio::ssl::context::default_workarounds + | asio::ssl::context::no_sslv2 + | asio::ssl::context::single_dh_use; + + if (!config_.sslEnableV3()) + sslOptions |= asio::ssl::context::no_sslv3; + + ssl_context_.set_options(sslOptions); + + if (config_.hasSslPasswordCallback()) + ssl_context_.set_password_callback(config_.sslPasswordCallback()); + + if (config_.sslClientVerification() == "none") { + ssl_context_.set_verify_mode(asio::ssl::context::verify_none); + } else if (config_.sslClientVerification() == "optional") { + ssl_context_.set_verify_mode(asio::ssl::context::verify_peer); + ssl_context_.load_verify_file(config_.sslCaCertificates()); + } else { + // assume 'required' + ssl_context_.set_verify_mode(asio::ssl::context::verify_peer | + asio::ssl::context::verify_fail_if_no_peer_cert); + ssl_context_.load_verify_file(config_.sslCaCertificates()); + } + + if(config_.hasSslCallbackProvide()) + { + X509* pCert = NULL; + EVP_PKEY* pPrvKey = NULL; + int ret = config_.sslProvideCallback()(pCert, pPrvKey); + ::SSL_CTX_use_certificate(ssl_context_.native_handle(), pCert); + ::SSL_CTX_use_PrivateKey(ssl_context_.native_handle(), pPrvKey); + } + else + { + ssl_context_.use_certificate_chain_file(config_.sslCertificateChainFile()); + ssl_context_.use_private_key_file(config_.sslPrivateKeyFile(),asio::ssl::context::pem); + } + + ssl_context_.use_tmp_dh_file(config_.sslTmpDHFile()); + + SSL_CTX *native_ctx = nativeContext(ssl_context_); + + if (config_.sslCipherList().size()) { + if (!SSL_CTX_set_cipher_list(native_ctx, config_.sslCipherList().c_str())) { + throw Wt::WServer::Exception( + "failed to select ciphers for cipher list " + + config_.sslCipherList()); + } + } + + std::string sessionId = Wt::WRandom::generateId(SSL_MAX_SSL_SESSION_ID_LENGTH); + SSL_CTX_set_session_id_context(native_ctx, + reinterpret_cast(sessionId.c_str()), sessionId.size()); + + asio::ip::tcp::endpoint ssl_endpoint; +#ifndef NO_RESOLVE_ACCEPT_ADDRESS + asio::ip::tcp::resolver::query ssl_query(config_.httpsAddress(), + config_.httpsPort()); + ssl_endpoint = *resolver.resolve(ssl_query); +#else // !NO_RESOLVE_ACCEPT_ADDRESS + ssl_endpoint.address(asio::ip::address::from_string(config_.httpsAddress())); + ssl_endpoint.port(atoi(httpsPort.c_str())); +#endif // NO_RESOLVE_ACCEPT_ADDRESS + + ssl_acceptor_.open(ssl_endpoint.protocol()); + ssl_acceptor_.set_option(asio::ip::tcp::acceptor::reuse_address(true)); + try { + ssl_acceptor_.bind(ssl_endpoint); + } catch (boost::system::system_error e) { + LOG_ERROR_S(&wt_, bindError(ssl_endpoint, e);) + throw; + } + ssl_acceptor_.listen(); + + new_sslconnection_.reset + (new SslConnection(wt_.ioService(), this, ssl_context_, connection_manager_, + request_handler_)); + +#else // HTTP_WITH_SSL + LOG_ERROR_S(&wt_, "built without support for SSL: " + "cannot start https server."); +#endif // HTTP_WITH_SSL + } + + // Win32 cancels the non-blocking accept when the thread that called + // accept exits. To avoid that this happens when called within the + // WServer context, we post the action of calling accept to one of + // the threads in the threadpool. + wt_.ioService().post(boost::bind(&Server::startAccept, this)); +} + +int Server::httpPort() const +{ + return tcp_acceptor_.local_endpoint().port(); +} + +void Server::startAccept() +{ + /* + * For simplicity, we are using the same accept_strand_ for Tcp + * and Ssl, to prevent the close() from within handleStop() and + * async_accept() methods to be called simultaneously. + * + * While this also prevents simultaneously accepting a new Tcp and + * Ssl connection, this performance impact is negligible (and both + * need to access the ConnectionManager mutex in any case). + */ + if (new_tcpconnection_) { + tcp_acceptor_.async_accept(new_tcpconnection_->socket(), + accept_strand_.wrap( + boost::bind(&Server::handleTcpAccept, this, + asio::placeholders::error))); + } + +#ifdef HTTP_WITH_SSL + if (new_sslconnection_) { + ssl_acceptor_.async_accept(new_sslconnection_->socket(), + accept_strand_.wrap( + boost::bind(&Server::handleSslAccept, this, + asio::placeholders::error))); + } +#endif // HTTP_WITH_SSL +} + +Server::~Server() +{ } + +void Server::stop() +{ + // Post a call to the stop function so that server::stop() is safe + // to call from any thread, and not simultaneously with waiting for + // a new async_accept() call. + wt_.ioService().post(accept_strand_.wrap + (boost::bind(&Server::handleStop, this))); +} + +void Server::resume() +{ + wt_.ioService().post(boost::bind(&Server::handleResume, this)); +} + +void Server::handleResume() +{ + tcp_acceptor_.close(); + +#ifdef HTTP_WITH_SSL + ssl_acceptor_.close(); +#endif // HTTP_WITH_SSL + + start(); +} + +void Server::handleTcpAccept(const asio_error_code& e) +{ + if (!e) { + connection_manager_.start(new_tcpconnection_); + new_tcpconnection_.reset(new TcpConnection(wt_.ioService(), this, + connection_manager_, request_handler_)); + tcp_acceptor_.async_accept(new_tcpconnection_->socket(), + accept_strand_.wrap( + boost::bind(&Server::handleTcpAccept, this, + asio::placeholders::error))); + } +} + +#ifdef HTTP_WITH_SSL +void Server::handleSslAccept(const asio_error_code& e) +{ + if (!e) + { + connection_manager_.start(new_sslconnection_); + new_sslconnection_.reset(new SslConnection(wt_.ioService(), this, + ssl_context_, connection_manager_, request_handler_)); + ssl_acceptor_.async_accept(new_sslconnection_->socket(), + accept_strand_.wrap( + boost::bind(&Server::handleSslAccept, this, + asio::placeholders::error))); + } +} +#endif // HTTP_WITH_SSL + +void Server::handleStop() +{ + // The server is stopped by cancelling all outstanding asynchronous + // operations. Once all operations have finished the io_service::run() call + // will exit. + tcp_acceptor_.close(); + +#ifdef HTTP_WITH_SSL + ssl_acceptor_.close(); +#endif // HTTP_WITH_SSL + + connection_manager_.stopAll(); +} + +} // namespace server +} // namespace http Index: http/WServer.C =================================================================== --- http/WServer.C (revision 5) +++ http/WServer.C (working copy) @@ -64,6 +64,7 @@ { delete serverConfiguration_; ssl_pw_cb_.clear(); + ssl_provide_cb_.clear(); } http::server::Configuration *serverConfiguration_; @@ -70,6 +71,7 @@ http::server::Server *server_; WServer::ssl_password_cb_t ssl_pw_cb_; + WServer::ssl_provide_cb_t ssl_provide_cb_; }; WServer::WServer(const std::string& applicationPath, @@ -155,6 +157,11 @@ impl_->serverConfiguration_->setSslPasswordCallback(impl_->ssl_pw_cb_); } + if (impl_->ssl_provide_cb_) + { + impl_->serverConfiguration_->setSslProvideCallback(impl_->ssl_provide_cb_); + } + impl_->server_ = new http::server::Server(*impl_->serverConfiguration_, *this); @@ -245,6 +252,11 @@ impl_->ssl_pw_cb_ = cb; } +void WServer::setSslProvideCallback(ssl_provide_cb_t cb) +{ + impl_->ssl_provide_cb_ = cb; +} + int WRun(int argc, char *argv[], ApplicationCreator createApplication) { try { Index: Wt/WServer =================================================================== --- Wt/WServer (revision 5) +++ Wt/WServer (working copy) @@ -11,6 +11,11 @@ #include #include +struct x509_st; +typedef struct x509_st X509; +struct evp_pkey_st; +typedef struct evp_pkey_st EVP_PKEY; + namespace Wt { class Configuration; @@ -77,6 +82,11 @@ * Callback used for reading SSL private keys protected with password */ typedef boost::function ssl_password_cb_t; + + /*! \brief + * Callback used for reading SSL certificate and private key + */ + typedef boost::function ssl_provide_cb_t; /*! \class Exception * \brief Server %Exception class. @@ -356,6 +366,8 @@ * underlying implementation will truncate the password to this length. */ WT_API void setSslPasswordCallback(ssl_password_cb_t cb); + + WT_API void setSslProvideCallback(ssl_provide_cb_t cb); #endif // WT_TARGET_JAVA