From 960e8d017b264710e344c63f9feb6ea1fa593eeb Mon Sep 17 00:00:00 2001 From: Roel Standaert Date: Tue, 19 Dec 2017 17:33:41 +0100 Subject: [PATCH] Several changes: - Compatibility with Boost 1.66 (asio changes) - WDialog: Document that autofocus is enabled by default, and don't change focus if it was set explicitly - Fix findById - WWebWidget: Avoid copy of children vector - Json: Document headers to include for Wt::Json::parse() and Wt::Json::serialize() - does not exist anymore as a child of or --- examples/filetreetable/CMakeLists.txt | 1 + examples/gitmodel/CMakeLists.txt | 2 +- examples/wt-homepage/CMakeLists.txt | 2 +- src/Wt/AsioWrapper/strand.hpp | 19 +++++++++++++++++ src/Wt/Http/Client.C | 8 ++++++- src/Wt/Http/Client.h | 5 +++++ src/Wt/Json/Value.h | 5 ++++- src/Wt/WDialog.C | 6 ++++-- src/Wt/WDialog.h | 3 +++ src/Wt/WWebWidget.C | 12 ++++++++--- src/http/Connection.C | 39 +++++++++++++++++++++-------------- src/http/Connection.h | 8 +++++-- src/http/Reply.C | 3 ++- src/http/Server.C | 4 ++++ src/http/Server.h | 2 +- src/http/SessionProcess.C | 5 +++++ src/http/SslConnection.C | 16 +++++++------- src/http/TcpConnection.C | 18 ++++++++-------- src/web/Configuration.C | 4 ---- 19 files changed, 113 insertions(+), 49 deletions(-) diff --git a/examples/filetreetable/CMakeLists.txt b/examples/filetreetable/CMakeLists.txt index 4265b9b7..c0c94100 100644 --- a/examples/filetreetable/CMakeLists.txt +++ b/examples/filetreetable/CMakeLists.txt @@ -10,6 +10,7 @@ ELSE(NOT BOOST_FS_LIB) TARGET_LINK_LIBRARIES(filetreetable.wt ${BOOST_FS_LIB} + ${BOOST_SYSTEM_LIB} ) INCLUDE_DIRECTORIES(${WT_SOURCE_DIR}/src) diff --git a/examples/gitmodel/CMakeLists.txt b/examples/gitmodel/CMakeLists.txt index 9b124c98..ed557d1f 100644 --- a/examples/gitmodel/CMakeLists.txt +++ b/examples/gitmodel/CMakeLists.txt @@ -7,7 +7,7 @@ IF(BOOST_FS_LIB) ../wt-homepage/SourceView.C GitView.C ) - TARGET_LINK_LIBRARIES(gitview.wt ${BOOST_FS_LIB}) + TARGET_LINK_LIBRARIES(gitview.wt ${BOOST_FS_LIB} ${BOOST_SYSTEM_LIB}) INCLUDE_DIRECTORIES( ${WT_SOURCE_DIR}/src diff --git a/examples/wt-homepage/CMakeLists.txt b/examples/wt-homepage/CMakeLists.txt index b60e7c5f..513bc570 100644 --- a/examples/wt-homepage/CMakeLists.txt +++ b/examples/wt-homepage/CMakeLists.txt @@ -34,7 +34,7 @@ ENDIF(WT_EMWEB_BUILD) WT_ADD_EXAMPLE(Home.wt ${SRC}) -TARGET_LINK_LIBRARIES(Home.wt ${EXAMPLES_DBO_LIBS} ${BOOST_FS_LIB}) +TARGET_LINK_LIBRARIES(Home.wt ${EXAMPLES_DBO_LIBS} ${BOOST_FS_LIB} ${BOOST_SYSTEM_LIB}) # Test whether crypt(3) is provided by libc. If it's not, check if # libcrypt exists and if it provides crypt(3). diff --git a/src/Wt/AsioWrapper/strand.hpp b/src/Wt/AsioWrapper/strand.hpp index 0c3a201f..9ddd8d1b 100644 --- a/src/Wt/AsioWrapper/strand.hpp +++ b/src/Wt/AsioWrapper/strand.hpp @@ -12,10 +12,29 @@ #ifdef WT_ASIO_IS_BOOST_ASIO #include +namespace Wt { + namespace AsioWrapper { +#if BOOST_VERSION >= 106600 + using strand = boost::asio::io_context::strand; +#else + using strand = boost::asio::strand; +#endif + } +} #else // WT_ASIO_IS_STANDALONE_ASIO +#include #include +namespace Wt { + namespace AsioWrapper { +#if ASIO_VERSION >= 101100 + using strand = asio::io_service::strand; +#else + using strand = asio::strand; +#endif + } +} #endif // WT_ASIO_IS_BOOST_ASIO diff --git a/src/Wt/Http/Client.C b/src/Wt/Http/Client.C index 85230d10..6bb21a95 100644 --- a/src/Wt/Http/Client.C +++ b/src/Wt/Http/Client.C @@ -642,7 +642,7 @@ private: protected: asio::io_service& ioService_; - asio::strand strand_; + AsioWrapper::strand strand_; tcp::resolver resolver_; asio::streambuf requestBuf_; asio::streambuf responseBuf_; @@ -929,8 +929,14 @@ bool Client::request(Http::Method method, const std::string& url, #ifdef WT_WITH_SSL } else if (parsedUrl.protocol == "https") { +#if defined(WT_ASIO_IS_BOOST_ASIO) && BOOST_VERSION >= 106600 + asio::ssl::context context(asio::ssl::context::tls); +#elif defined(WT_ASIO_IS_STANDALONE_ASIO) && ASIO_VERSION >= 101100 + asio::ssl::context context(asio::ssl::context::sslv23); +#else asio::ssl::context context (*ioService, asio::ssl::context::sslv23); +#endif long sslOptions = asio::ssl::context::no_sslv2 | asio::ssl::context::no_sslv3; context.set_options(sslOptions); diff --git a/src/Wt/Http/Client.h b/src/Wt/Http/Client.h index f3c7169a..77946867 100644 --- a/src/Wt/Http/Client.h +++ b/src/Wt/Http/Client.h @@ -23,7 +23,12 @@ #ifdef WT_ASIO_IS_BOOST_ASIO namespace boost { namespace asio { +#if BOOST_VERSION >= 106600 + class io_context; + typedef io_context io_service; +#else class io_service; +#endif } } #else // WT_ASIO_IS_STANDALONE_ASIO diff --git a/src/Wt/Json/Value.h b/src/Wt/Json/Value.h index 948277fa..0b0bc0d7 100644 --- a/src/Wt/Json/Value.h +++ b/src/Wt/Json/Value.h @@ -23,7 +23,7 @@ class Array; * \brief A JSON representation and parsing library. * * The JSON library contains data types to represent a JSON data - * structure (Value, Object and Array), and a JSON parser. + * structure (Value, Object and Array), a JSON parser, and a JSON serializer. * * Usage example: * \code @@ -39,6 +39,9 @@ class Array; * bool b = result.get("b"); * std::cerr << "a: " << s << ", b: " << b << std::endl; // a: That's great, b: true * \endcode + * + * Include the header for Wt::Json::parse(), and + * the header for Wt::Json::serialize(). */ /*! \brief Enumeration for the type of a JSON value. diff --git a/src/Wt/WDialog.C b/src/Wt/WDialog.C index 65ba51d7..31bd88b0 100644 --- a/src/Wt/WDialog.C +++ b/src/Wt/WDialog.C @@ -436,8 +436,10 @@ void WDialog::render(WFlags flags) if (!isModal()) impl_->mouseWentDown().connect(this, &WDialog::bringToFront); - if ( flags.test(RenderFlag::Full) && autoFocus_) - impl_->setFirstFocus(); + if ( flags.test(RenderFlag::Full) && autoFocus_) { + if (!impl_->findById(Wt::WApplication::instance()->focus())) + impl_->setFirstFocus(); + } WPopupWidget::render(flags); } diff --git a/src/Wt/WDialog.h b/src/Wt/WDialog.h index 810d6945..967087c8 100644 --- a/src/Wt/WDialog.h +++ b/src/Wt/WDialog.h @@ -337,6 +337,9 @@ class WT_API WDialog : public WPopupWidget bool closable() const { return closeIcon_ != nullptr; } /*! \brief Set focus on the first widget in the dialog. + * + * Autofocus is enabled by default. If a widget inside of + * this dialog already has focus, the focus will not be changed. */ void setAutoFocus(bool enable){ autoFocus_ = enable;} diff --git a/src/Wt/WWebWidget.C b/src/Wt/WWebWidget.C index 42fc00fd..5835244f 100644 --- a/src/Wt/WWebWidget.C +++ b/src/Wt/WWebWidget.C @@ -1983,9 +1983,13 @@ bool WWebWidget::setFirstFocus() return true; } - for (unsigned i = 0; i < children().size(); i++) - if (children()[i]->setFirstFocus()) - return true; + bool result = false; + iterateChildren([&result](Wt::WWidget *w){ + if (!result) + result = w->setFirstFocus(); + }); + if (result) + return true; return false; } else @@ -2207,6 +2211,8 @@ WWidget *WWebWidget::findById(const std::string& id) if (!result) result = c->findById(id); }); + if (result) + return result; } return nullptr; diff --git a/src/http/Connection.C b/src/http/Connection.C index cab77089..27380a8a 100644 --- a/src/http/Connection.C +++ b/src/http/Connection.C @@ -61,6 +61,15 @@ Connection::~Connection() LOG_DEBUG("~Connection"); } +asio::ip::tcp::socket::native_handle_type Connection::native() +{ +#if (defined(WT_ASIO_IS_BOOST_ASIO) && BOOST_VERSION >= 106600) || (defined(WT_ASIO_IS_STANDALONE_ASIO) && ASIO_VERSION >= 101100) + return socket().native_handle(); +#else + return socket().native(); +#endif +} + void Connection::finishReply() { if (!request_.uri.empty()) { @@ -78,7 +87,7 @@ void Connection::scheduleStop() void Connection::start() { - LOG_DEBUG(socket().native() << ": start()"); + LOG_DEBUG(native() << ": start()"); request_parser_.reset(); request_.reset(); @@ -106,7 +115,7 @@ void Connection::stop() void Connection::setReadTimeout(int seconds) { if (seconds != 0) { - LOG_DEBUG(socket().native() << " setting read timeout (ws: " + LOG_DEBUG(native() << " setting read timeout (ws: " << request_.webSocketVersion << ")"); state_ |= Reading; @@ -118,7 +127,7 @@ void Connection::setReadTimeout(int seconds) void Connection::setWriteTimeout(int seconds) { - LOG_DEBUG(socket().native() << " setting write timeout (ws: " + LOG_DEBUG(native() << " setting write timeout (ws: " << request_.webSocketVersion << ")"); state_ |= Writing; @@ -129,7 +138,7 @@ void Connection::setWriteTimeout(int seconds) void Connection::cancelReadTimer() { - LOG_DEBUG(socket().native() << " cancel read timeout"); + LOG_DEBUG(native() << " cancel read timeout"); state_.clear(Reading); readTimer_.cancel(); @@ -137,7 +146,7 @@ void Connection::cancelReadTimer() void Connection::cancelWriteTimer() { - LOG_DEBUG(socket().native() << " cancel write timeout"); + LOG_DEBUG(native() << " cancel write timeout"); state_.clear(Writing); writeTimer_.cancel(); @@ -163,7 +172,7 @@ void Connection::handleReadRequest0() #ifdef DEBUG try { - LOG_DEBUG(socket().native() << "incoming request: " + LOG_DEBUG(socket().native_handle() << "incoming request: " << socket().remote_endpoint().port() << " (avail= " << (rcv_buffer_size_ - (rcv_remaining_ - buffer.data())) << "): " << std::string(rcv_remaining_, @@ -189,7 +198,7 @@ void Connection::handleReadRequest0() if (doWebSockets) request_.enableWebSocket(); - LOG_DEBUG(socket().native() << "request: " << status); + LOG_DEBUG(native() << "request: " << status); if (status >= 300) sendStockReply(status); @@ -242,7 +251,7 @@ void Connection::sendStockReply(StockReply::status_type status) void Connection::handleReadRequest(const Wt::AsioWrapper::error_code& e, std::size_t bytes_transferred) { - LOG_DEBUG(socket().native() << ": handleReadRequest(): " << e.message()); + LOG_DEBUG(native() << ": handleReadRequest(): " << e.message()); cancelReadTimer(); @@ -261,7 +270,7 @@ void Connection::close() cancelReadTimer(); cancelWriteTimer(); - LOG_DEBUG(socket().native() << ": close()"); + LOG_DEBUG(native() << ": close()"); ConnectionManager_.stop(shared_from_this()); } @@ -274,7 +283,7 @@ bool Connection::closed() const void Connection::handleError(const Wt::AsioWrapper::error_code& e) { - LOG_DEBUG(socket().native() << ": error: " << e.message()); + LOG_DEBUG(native() << ": error: " << e.message()); close(); } @@ -349,7 +358,7 @@ void Connection::handleReadBody0(ReplyPtr reply, const Wt::AsioWrapper::error_code& e, std::size_t bytes_transferred) { - LOG_DEBUG(socket().native() << ": handleReadBody0(): " << e.message()); + LOG_DEBUG(native() << ": handleReadBody0(): " << e.message()); if (disconnectCallback_) { if (e && e != asio::error::operation_aborted) { @@ -357,7 +366,7 @@ void Connection::handleReadBody0(ReplyPtr reply, disconnectCallback_ = boost::function(); f(); } else if (!e) { - LOG_ERROR(socket().native() + LOG_ERROR(native() << ": handleReadBody(): while waiting for disconnect, " "received unexpected data, closing"); close(); @@ -410,7 +419,7 @@ void Connection::startWriteResponse(ReplyPtr reply) } #endif - LOG_DEBUG(socket().native() << " sending: " << s << "(buffers: " + LOG_DEBUG(native() << " sending: " << s << "(buffers: " << buffers.size() << ")"); if (!buffers.empty()) { @@ -423,7 +432,7 @@ void Connection::startWriteResponse(ReplyPtr reply) void Connection::handleWriteResponse(ReplyPtr reply) { - LOG_DEBUG(socket().native() << ": handleWriteResponse() " << + LOG_DEBUG(native() << ": handleWriteResponse() " << haveResponse_ << " " << responseDone_); if (haveResponse_) startWriteResponse(reply); @@ -458,7 +467,7 @@ void Connection::handleWriteResponse0(ReplyPtr reply, const Wt::AsioWrapper::error_code& e, std::size_t bytes_transferred) { - LOG_DEBUG(socket().native() << ": handleWriteResponse0(): " + LOG_DEBUG(native() << ": handleWriteResponse0(): " << bytes_transferred << " ; " << e.message()); cancelWriteTimer(); diff --git a/src/http/Connection.h b/src/http/Connection.h index b0b71a36..f925177c 100644 --- a/src/http/Connection.h +++ b/src/http/Connection.h @@ -18,6 +18,7 @@ #define HTTP_CONNECTION_HPP #include +#include #include #include "Buffer.h" @@ -61,7 +62,7 @@ class Connection : public std::enable_shared_from_this virtual ~Connection(); Server *server() const { return server_; } - asio::strand& strand() { return strand_; } + Wt::AsioWrapper::strand& strand() { return strand_; } /// Stop all asynchronous operations associated with the connection. void scheduleStop(); @@ -86,6 +87,9 @@ class Connection : public std::enable_shared_from_this const std::function& callback); protected: + /// Get the native handle of the socket + asio::ip::tcp::socket::native_handle_type native(); + void handleWriteResponse0(ReplyPtr reply, const Wt::AsioWrapper::error_code& e, std::size_t bytes_transferred); @@ -104,7 +108,7 @@ class Connection : public std::enable_shared_from_this /// The manager for this connection. ConnectionManager& ConnectionManager_; - asio::strand strand_; + Wt::AsioWrapper::strand strand_; void finishReply(); diff --git a/src/http/Reply.C b/src/http/Reply.C index 0d79e39f..b55ece21 100644 --- a/src/http/Reply.C +++ b/src/http/Reply.C @@ -596,7 +596,8 @@ bool Reply::encodeNextContentBuffer( originalSize += bs; gzipStrm_.avail_in = bs; - gzipStrm_.next_in = (unsigned char *)asio::detail::buffer_cast_helper(b); + gzipStrm_.next_in = const_cast( + asio::buffer_cast(b)); unsigned char out[16*1024]; do { diff --git a/src/http/Server.C b/src/http/Server.C index fc69be21..ad16591f 100644 --- a/src/http/Server.C +++ b/src/http/Server.C @@ -116,7 +116,11 @@ Server::Server(const Configuration& config, Wt::WServer& wtServer) accept_strand_(wt_.ioService()), // post_strand_(ioService_), #ifdef HTTP_WITH_SSL +#if (defined(WT_ASIO_IS_BOOST_ASIO) && BOOST_VERSION >= 106600) || (defined(WT_ASIO_IS_STANDALONE_ASIO) && ASIO_VERSION >= 101100) + ssl_context_(asio::ssl::context::sslv23), +#else ssl_context_(wt_.ioService(), asio::ssl::context::sslv23), +#endif #endif // HTTP_WITH_SSL connection_manager_(), sessionManager_(0), diff --git a/src/http/Server.h b/src/http/Server.h index 3d3229ac..97387b11 100644 --- a/src/http/Server.h +++ b/src/http/Server.h @@ -129,7 +129,7 @@ class Server Wt::WLogger accessLogger_; /// The strand for handleTcpAccept(), handleSslAccept() and handleStop() - asio::strand accept_strand_; + Wt::AsioWrapper::strand accept_strand_; /// Acceptors used to listen for incoming http connections. std::vector tcp_listeners_; diff --git a/src/http/SessionProcess.C b/src/http/SessionProcess.C index 72d9a881..fb057f2f 100644 --- a/src/http/SessionProcess.C +++ b/src/http/SessionProcess.C @@ -16,6 +16,7 @@ #include #endif // WT_WIN32 +#include "Wt/WConfig.h" #include "Wt/WLogger.h" namespace Wt { @@ -80,7 +81,11 @@ void SessionProcess::asyncExec(const Configuration &config, if (!ec) acceptor_->listen(0, ec); #ifndef WT_WIN32 +#if (defined(WT_ASIO_IS_BOOST_ASIO) && BOOST_VERSION >= 106600) || (defined(WT_ASIO_IS_STANDALONE_ASIO) && ASIO_VERSION >= 101100) + fcntl(acceptor_->native_handle(), F_SETFD, FD_CLOEXEC); +#else fcntl(acceptor_->native(), F_SETFD, FD_CLOEXEC); +#endif #endif // !WT_WIN32 if (ec) { LOG_ERROR("Couldn't create listening socket: " << ec.message()); diff --git a/src/http/SslConnection.C b/src/http/SslConnection.C index 74c8642a..12eb7465 100644 --- a/src/http/SslConnection.C +++ b/src/http/SslConnection.C @@ -81,9 +81,9 @@ void SslConnection::handleHandshake(const Wt::AsioWrapper::error_code& error) void SslConnection::stop() { - LOG_DEBUG(socket().native() << ": stop()"); + LOG_DEBUG(native() << ": stop()"); finishReply(); - LOG_DEBUG(socket().native() << ": SSL shutdown"); + LOG_DEBUG(native() << ": SSL shutdown"); Connection::stop(); @@ -108,20 +108,20 @@ void SslConnection::stopNextLayer(const Wt::AsioWrapper::error_code& ec) // In case of timeout, we will get here twice. sslShutdownTimer_.cancel(); if (ec) { - LOG_DEBUG(socket().native() << ": ssl_shutdown failed:" + LOG_DEBUG(native() << ": ssl_shutdown failed:" << ec.message()); } try { if (socket().is_open()) { Wt::AsioWrapper::error_code ignored_ec; - LOG_DEBUG(socket().native() << ": socket shutdown"); + LOG_DEBUG(native() << ": socket shutdown"); socket().shutdown(asio::ip::tcp::socket::shutdown_both, ignored_ec); - LOG_DEBUG(socket().native() << "closing socket"); + LOG_DEBUG(native() << "closing socket"); socket().close(); } } catch (Wt::AsioWrapper::system_error& e) { - LOG_DEBUG(socket().native() << ": error " << e.what()); + LOG_DEBUG(native() << ": error " << e.what()); } } @@ -161,7 +161,7 @@ void SslConnection::startAsyncReadBody(ReplyPtr reply, Buffer& buffer, int timeout) { if (state_ & Reading) { - LOG_DEBUG(socket().native() << ": state_ = " + LOG_DEBUG(native() << ": state_ = " << (state_ & Reading ? "reading " : "") << (state_ & Writing ? "writing " : "")); stop(); @@ -198,7 +198,7 @@ void SslConnection int timeout) { if (state_ & Writing) { - LOG_DEBUG(socket().native() << ": state_ = " + LOG_DEBUG(native() << ": state_ = " << (state_ & Reading ? "reading " : "") << (state_ & Writing ? "writing " : "")); stop(); diff --git a/src/http/TcpConnection.C b/src/http/TcpConnection.C index ad731647..ab2476ed 100644 --- a/src/http/TcpConnection.C +++ b/src/http/TcpConnection.C @@ -38,17 +38,17 @@ asio::ip::tcp::socket& TcpConnection::socket() void TcpConnection::stop() { - LOG_DEBUG(socket().native() << ": stop()"); + LOG_DEBUG(native() << ": stop()"); finishReply(); try { Wt::AsioWrapper::error_code ignored_ec; socket_.shutdown(asio::ip::tcp::socket::shutdown_both, ignored_ec); - LOG_DEBUG(socket().native() << ": closing socket"); + LOG_DEBUG(native() << ": closing socket"); socket_.close(); } catch (Wt::AsioWrapper::system_error& e) { - LOG_DEBUG(socket().native() << ": error " << e.what()); + LOG_DEBUG(native() << ": error " << e.what()); } Connection::stop(); @@ -56,10 +56,10 @@ void TcpConnection::stop() void TcpConnection::startAsyncReadRequest(Buffer& buffer, int timeout) { - LOG_DEBUG(socket().native() << ": startAsyncReadRequest"); + LOG_DEBUG(native() << ": startAsyncReadRequest"); if (state_ & Reading) { - LOG_DEBUG(socket().native() << ": state_ = " + LOG_DEBUG(native() << ": state_ = " << (state_ & Reading ? "reading " : "") << (state_ & Writing ? "writing " : "")); stop(); @@ -81,10 +81,10 @@ void TcpConnection::startAsyncReadRequest(Buffer& buffer, int timeout) void TcpConnection::startAsyncReadBody(ReplyPtr reply, Buffer& buffer, int timeout) { - LOG_DEBUG(socket().native() << ": startAsyncReadBody"); + LOG_DEBUG(native() << ": startAsyncReadBody"); if (state_ & Reading) { - LOG_DEBUG(socket().native() << ": state_ = " + LOG_DEBUG(native() << ": state_ = " << (state_ & Reading ? "reading " : "") << (state_ & Writing ? "writing " : "")); stop(); @@ -109,10 +109,10 @@ void TcpConnection::startAsyncWriteResponse const std::vector& buffers, int timeout) { - LOG_DEBUG(socket().native() << ": startAsyncWriteResponse"); + LOG_DEBUG(native() << ": startAsyncWriteResponse"); if (state_ & Writing) { - LOG_DEBUG(socket().native() << ": state_ = " + LOG_DEBUG(native() << ": state_ = " << (state_ & Reading ? "reading " : "") << (state_ & Writing ? "writing " : "")); stop(); diff --git a/src/web/Configuration.C b/src/web/Configuration.C index 6b6507b7..e5f06505 100644 --- a/src/web/Configuration.C +++ b/src/web/Configuration.C @@ -825,14 +825,10 @@ void Configuration::readApplicationSettings(xml_node<> *app) runDirectory_ = singleChildElementValue(fcgi, "run-directory", runDirectory_); - setInt(fcgi, "num-threads", numThreads_); // backward compatibility < 3.2.0 - xml_node<> *isapi = singleChildElement(app, "connector-isapi"); if (!isapi) isapi = app; // backward compatibility - setInt(isapi, "num-threads", numThreads_); // backward compatibility < 3.2.0 - std::string maxMemoryRequestSizeStr = singleChildElementValue(isapi, "max-memory-request-size", ""); if (!maxMemoryRequestSizeStr.empty()) {