+
+#include "Poco/Net/HTTPReactorServer.h"
+
+
+using Poco::Net::ServerSocket;
+using Poco::Net::HTTPRequestHandler;
+using Poco::Net::HTTPRequestHandlerFactory;
+using Poco::Net::HTTPServer;
+using Poco::Net::HTTPServerRequest;
+using Poco::Net::HTTPServerResponse;
+using Poco::Net::HTTPServerParams;
+using Poco::Timestamp;
+using Poco::DateTimeFormatter;
+using Poco::DateTimeFormat;
+using Poco::ThreadPool;
+using Poco::Util::ServerApplication;
+using Poco::Util::Application;
+using Poco::Util::Option;
+using Poco::Util::OptionSet;
+using Poco::Util::HelpFormatter;
+
+
+class TimeRequestHandler: public HTTPRequestHandler
+ /// Return a HTML document with the current date and time.
+{
+public:
+ TimeRequestHandler(const std::string& format, long delay) : _format(format), _delay(delay)
+ {
+ }
+
+ void handleRequest(HTTPServerRequest& request, HTTPServerResponse& response)
+ {
+ Application& app = Application::instance();
+ app.logger().information("Request from " + request.clientAddress().toString());
+
+ Timestamp now;
+ std::string dt(DateTimeFormatter::format(now, _format));
+
+ response.setChunkedTransferEncoding(true);
+ response.setContentType("text/html");
+ response.set("Clear-Site-Data", "\"cookies\"");
+
+ Poco::Thread::sleep(_delay);
+
+ std::ostream& ostr = response.send();
+ ostr << "HTTPReactorTimeServer powered by POCO C++ Libraries";
+ ostr << "";
+ ostr << "";
+ ostr << dt;
+ ostr << "
";
+ }
+
+private:
+ std::string _format;
+ long _delay;
+ HTTPServerParams::Ptr _params;
+};
+
+
+class TimeRequestHandlerFactory: public HTTPRequestHandlerFactory
+{
+public:
+ TimeRequestHandlerFactory(const std::string& format, long delay) : _format(format), _delay(delay)
+ {
+ }
+
+ HTTPRequestHandler* createRequestHandler(const HTTPServerRequest& request)
+ {
+ if (request.getURI() == "/")
+ return new TimeRequestHandler(_format, _delay);
+ else
+ return 0;
+ }
+
+private:
+ std::string _format;
+ long _delay;
+};
+
+
+class HTTPReactorTimeServer: public Poco::Util::ServerApplication
+ /// The main application class.
+ ///
+ /// This class handles command-line arguments and
+ /// configuration files.
+ /// Start the HTTPReactorTimeServer executable with the help
+ /// option (/help on Windows, --help on Unix) for
+ /// the available command line options.
+ ///
+ /// To use the sample configuration file (HTTPReactorTimeServer.properties),
+ /// copy the file to the directory where the HTTPReactorTimeServer executable
+ /// resides. If you start the debug version of the HTTPReactorTimeServer
+ /// (HTTPReactorTimeServerd[.exe]), you must also create a copy of the configuration
+ /// file named HTTPReactorTimeServerd.properties. In the configuration file, you
+ /// can specify the port on which the server is listening (default
+ /// 9980) and the format of the date/time string sent back to the client.
+ ///
+ /// To test the TimeServer you can use any web browser (http://localhost:9980/).
+{
+public:
+ HTTPReactorTimeServer(): _helpRequested(false)
+ {
+ }
+
+ ~HTTPReactorTimeServer()
+ {
+ }
+
+protected:
+ void initialize(Application& self)
+ {
+ loadConfiguration(); // load default configuration files, if present
+ ServerApplication::initialize(self);
+ }
+
+ void uninitialize()
+ {
+ ServerApplication::uninitialize();
+ }
+
+ void defineOptions(OptionSet& options)
+ {
+ ServerApplication::defineOptions(options);
+
+ options.addOption(
+ Option("help", "h", "display help information on command line arguments")
+ .required(false)
+ .repeatable(false));
+ }
+
+ void handleOption(const std::string& name, const std::string& value)
+ {
+ ServerApplication::handleOption(name, value);
+
+ if (name == "help")
+ _helpRequested = true;
+ }
+
+ void displayHelp()
+ {
+ HelpFormatter helpFormatter(options());
+ helpFormatter.setCommand(commandName());
+ helpFormatter.setUsage("OPTIONS");
+ helpFormatter.setHeader("A web server that serves the current date and time.");
+ helpFormatter.format(std::cout);
+ }
+
+ int main(const std::vector& args)
+ {
+ if (_helpRequested)
+ {
+ displayHelp();
+ }
+ else
+ {
+ // get parameters from configuration file
+ unsigned short port = (unsigned short) config().getInt("HTTPReactorTimeServer.port", 9980);
+ std::string format(config().getString("HTTPReactorTimeServer.format", DateTimeFormat::SORTABLE_FORMAT));
+ int delay = config().getInt("HTTPReactorTimeServer.delay", 0);
+ int maxQueued = config().getInt("HTTPReactorTimeServer.maxQueued", 100);
+ int maxThreads = config().getInt("HTTPReactorTimeServer.maxThreads", 4);
+ ThreadPool::defaultPool().addCapacity(maxThreads);
+
+ HTTPServerParams* pParams = new HTTPServerParams;
+ pParams->setMaxQueued(maxQueued);
+ pParams->setMaxThreads(maxThreads);
+ pParams->setReactorMode(true);
+ pParams->setAcceptorNum(1);
+ pParams->setUseSelfReactor(false);
+
+ // set-up a reactor HTTPServer instance
+ Poco::Net::HTTPReactorServer server(port, pParams, new TimeRequestHandlerFactory(format, delay));
+ // start the HTTPServer
+ server.start();
+
+ // wait for CTRL-C or kill
+ waitForTerminationRequest();
+ // Stop the HTTPServer
+ server.stop();
+ }
+ return Application::EXIT_OK;
+ }
+
+private:
+ bool _helpRequested;
+};
+
+
+int main(int argc, char** argv)
+{
+ HTTPReactorTimeServer app;
+ return app.run(argc, argv);
+}
diff --git a/Net/samples/Makefile b/Net/samples/Makefile
index 4285e4cb3..5798eeeb4 100644
--- a/Net/samples/Makefile
+++ b/Net/samples/Makefile
@@ -11,6 +11,7 @@ projects:
$(MAKE) -C TimeServer $(MAKECMDGOALS)
$(MAKE) -C httpget $(MAKECMDGOALS)
$(MAKE) -C HTTPTimeServer $(MAKECMDGOALS)
+ $(MAKE) -C HTTPReactorTimeServer $(MAKECMDGOALS)
$(MAKE) -C HTTPFormServer $(MAKECMDGOALS)
$(MAKE) -C HTTPLoadTest $(MAKECMDGOALS)
$(MAKE) -C download $(MAKECMDGOALS)
diff --git a/Net/src/HTTPReactorServer.cpp b/Net/src/HTTPReactorServer.cpp
new file mode 100644
index 000000000..14a9d80e5
--- /dev/null
+++ b/Net/src/HTTPReactorServer.cpp
@@ -0,0 +1,113 @@
+#include "Poco/Net/HTTPReactorServer.h"
+#include "Poco/Net/HTTPReactorServerSession.h"
+#include "Poco/Net/HTTPRequestHandler.h"
+#include "Poco/Net/HTTPSession.h"
+#include
+
+namespace Poco { namespace Net {
+
+HTTPReactorServer::HTTPReactorServer(int port, HTTPServerParams::Ptr pParams, HTTPRequestHandlerFactory::Ptr pFactory)
+ : _tcpReactorServer(port, pParams)
+{
+ _pParams = pParams;
+ _pFactory = pFactory;
+ _tcpReactorServer.setRecvMessageCallback([this](const TcpReactorConnectionPtr& conn) {
+ // Handle incoming message
+ this->onMessage(conn);
+ });
+}
+
+HTTPReactorServer::~HTTPReactorServer()
+{
+}
+
+void HTTPReactorServer::start()
+{
+ _tcpReactorServer.start();
+}
+
+void HTTPReactorServer::stop()
+{
+ _tcpReactorServer.stop();
+}
+
+void HTTPReactorServer::onMessage(const TcpReactorConnectionPtr& conn)
+{
+ try
+ {
+ // Handle read event
+ HTTPReactorServerSession session(conn->socket(), conn->buffer(), _pParams);
+ if (!session.checkRequestComplete())
+ {
+ return;
+ }
+ // Create request and response objects
+ HTTPServerResponseImpl response(session);
+ HTTPServerRequestImpl request(response, session, _pParams);
+ // Process request and generate response
+ Poco::Timestamp now;
+ response.setDate(now);
+ response.setVersion(request.getVersion());
+ response.setKeepAlive(request.getKeepAlive());
+ std::string server = _pParams->getSoftwareVersion();
+ if (!server.empty())
+ {
+ response.set("Server", server);
+ }
+ try
+ {
+ session.requestTrailer().clear();
+ session.responseTrailer().clear();
+ std::unique_ptr pHandler(_pFactory->createRequestHandler(request));
+ if (pHandler.get())
+ {
+ if (request.getExpectContinue() && response.getStatus() == HTTPResponse::HTTP_OK)
+ response.sendContinue();
+
+ pHandler->handleRequest(request, response);
+ session.setKeepAlive(_pParams->getKeepAlive() && response.getKeepAlive());
+ }
+ else
+ sendErrorResponse(session, HTTPResponse::HTTP_NOT_IMPLEMENTED);
+ }
+ catch (Poco::Exception& e)
+ {
+ if (!response.sent())
+ {
+ try
+ {
+ sendErrorResponse(
+ session,
+ e.code() == 0 ? HTTPResponse::HTTP_INTERNAL_SERVER_ERROR : HTTPResponse::HTTPStatus(e.code()));
+ }
+ catch (...)
+ {
+ }
+ }
+ throw;
+ }
+ }
+ catch (const Poco::Exception& ex)
+ {
+ onError(ex);
+ }
+}
+
+void HTTPReactorServer::sendErrorResponse(HTTPSession& session, HTTPResponse::HTTPStatus status)
+{
+ HTTPServerResponseImpl response(session);
+ response.setVersion(HTTPMessage::HTTP_1_1);
+ response.setStatusAndReason(status);
+ response.setKeepAlive(false);
+
+ session.setKeepAlive(false);
+}
+
+void HTTPReactorServer::onError(const Poco::Exception& ex)
+{
+ // Handle error
+ throw ex;
+}
+
+}} // namespace Poco::Net
+
diff --git a/Net/src/HTTPReactorServerSession.cpp b/Net/src/HTTPReactorServerSession.cpp
new file mode 100644
index 000000000..0692c62ae
--- /dev/null
+++ b/Net/src/HTTPReactorServerSession.cpp
@@ -0,0 +1,226 @@
+#include "Poco/Net/HTTPReactorServerSession.h"
+#include "Poco/Net/HTTPMessage.h"
+#include "Poco/String.h"
+#include
+
+namespace Poco {
+namespace Net {
+
+
+HTTPReactorServerSession::HTTPReactorServerSession(
+ const StreamSocket& socket, std::string& buf, HTTPServerParams::Ptr pParams)
+ : // do not deliver socket to HTTPSession
+ HTTPSession(), _buf(buf), _realsocket(socket), _complete(0), _idx(0)
+{
+ _pcur = const_cast(_buf.c_str());
+ _idx = 0;
+}
+/// Creates the HTTPReactorServerSession.
+
+HTTPReactorServerSession::~HTTPReactorServerSession()
+{
+ if (_complete > 0)
+ {
+ popCompletedRequest();
+ }
+};
+/// Destroys the HTTPReactorServerSession.
+
+bool HTTPReactorServerSession::checkRequestComplete()
+{
+ enum State { PARSING_HEADERS, PARSING_CHUNK_SIZE, PARSING_CHUNK_DATA, PARSING_BODY, COMPLETE };
+
+ State state = PARSING_HEADERS;
+ std::size_t pos = 0;
+ std::size_t bodyStart = 0;
+ std::size_t contentLength = 0;
+ std::size_t chunkSize = 0;
+
+ while (pos < _buf.size())
+ {
+ switch (state)
+ {
+ case PARSING_HEADERS:
+ {
+ bool isChunked = false;
+ if (!parseHeaders(pos, bodyStart, contentLength, isChunked))
+ return false;
+ if (isChunked)
+ {
+ state = PARSING_CHUNK_SIZE;
+ pos = bodyStart;
+ } else if (contentLength > 0)
+ {
+ state = PARSING_BODY;
+ pos = bodyStart;
+ } else
+ {
+ _complete = bodyStart;
+ return true;
+ }
+ break;
+ }
+ case PARSING_CHUNK_SIZE:
+ {
+ if (!parseChunkSize(pos, chunkSize, _complete))
+ return false;
+ if (chunkSize == 0)
+ return true;
+ state = PARSING_CHUNK_DATA;
+ break;
+ }
+ case PARSING_CHUNK_DATA:
+ {
+ if (pos + chunkSize + 2 <= _buf.size())
+ {
+ pos += chunkSize + 2; // Skip chunk data and trailing "\r\n"
+ state = PARSING_CHUNK_SIZE;
+ } else
+ {
+ return false; // Incomplete chunk data
+ }
+ break;
+ }
+ case PARSING_BODY:
+ {
+ if (_buf.size() >= bodyStart + contentLength)
+ {
+ _complete = bodyStart + contentLength;
+ return true;
+ }
+ return false; // Incomplete body
+ }
+ case COMPLETE:
+ return true;
+ }
+ }
+ return false; // Request is not complete
+}
+
+bool HTTPReactorServerSession::parseHeaders(
+ std::size_t pos, std::size_t& bodyStart, std::size_t& contentLength, bool& isChunked)
+{
+ std::size_t headerEnd = _buf.find("\r\n\r\n", pos);
+ if (headerEnd == std::string::npos)
+ {
+ return false; // Incomplete headers
+ }
+
+ bodyStart = headerEnd + 4; // "\r\n\r\n" is 4 characters
+ std::size_t chunkedPos = _buf.find(HTTPMessage::TRANSFER_ENCODING, pos);
+ if (chunkedPos == std::string::npos)
+ {
+ chunkedPos = _buf.find(toLower(HTTPMessage::TRANSFER_ENCODING), pos);
+ }
+ std::size_t chunkedVal = _buf.find(HTTPMessage::CHUNKED_TRANSFER_ENCODING, chunkedPos);
+ std::size_t chunkedLineEnd = _buf.find("\r\n", chunkedPos);
+ if (chunkedPos != std::string::npos && chunkedVal != std::string::npos &&
+ chunkedLineEnd != std::string::npos && chunkedVal < chunkedLineEnd)
+ {
+ isChunked = true;
+ return true;
+ }
+ std::size_t contentLengthPos = _buf.find(HTTPMessage::CONTENT_LENGTH, pos);
+ if(contentLengthPos == std::string::npos)
+ {
+ contentLengthPos = _buf.find(toLower(HTTPMessage::CONTENT_LENGTH), pos);
+ }
+ if (contentLengthPos != std::string::npos)
+ {
+ std::size_t valueStart = contentLengthPos + 15; // "Content-Length:" is 15 characters
+ std::size_t valueEnd = _buf.find("\r\n", valueStart);
+ if (valueEnd != std::string::npos)
+ {
+ contentLength = std::stoi(_buf.substr(valueStart, valueEnd - valueStart));
+ isChunked = false;
+ return true;
+ } else
+ {
+ return false; // Incomplete Content-Length header
+ }
+ }
+ contentLength = 0;
+ isChunked = false;
+ return true;
+}
+
+bool HTTPReactorServerSession::parseChunkSize(std::size_t& pos, std::size_t& chunkSize, int& complete)
+{
+
+ std::size_t chunkSizeEnd = _buf.find("\r\n", pos);
+ if (chunkSizeEnd == std::string::npos)
+ return false; // Incomplete chunk size
+
+ std::string chunkSizeStr = _buf.substr(pos, chunkSizeEnd - pos);
+ chunkSize = std::stoi(chunkSizeStr, nullptr, 16); // Parse hex chunk size
+ if (chunkSize == 0)
+ {
+ std::size_t finalChunkEnd = _buf.find("\r\n\r\n", chunkSizeEnd);
+ if (finalChunkEnd != std::string::npos)
+ {
+ complete = finalChunkEnd + 4; // End of "\r\n\r\n"
+ return true;
+ } else
+ {
+ return false; // Incomplete final "\r\n\r\n"
+ }
+ }
+ pos = chunkSizeEnd + 2; // Move to the chunk data
+
+ return true;
+}
+
+void HTTPReactorServerSession::popCompletedRequest()
+{
+ if (_complete >= _buf.length())
+ {
+ // All data has been processed
+ _buf.clear();
+ } else
+ {
+ _buf = _buf.substr(_complete);
+ }
+ _complete = 0;
+ _idx = 0;
+ _pcur = const_cast(_buf.c_str());
+ _pend = _pcur + _buf.length();
+}
+
+int HTTPReactorServerSession::get()
+{
+ if (_idx < _complete)
+ {
+ return _buf[_idx++];
+ } else
+ {
+ return std::char_traits::eof();
+ }
+}
+
+int HTTPReactorServerSession::peek()
+{
+ if (_idx < _complete)
+ {
+
+ return _buf[_idx];
+ } else
+ {
+
+ return std::char_traits::eof();
+ }
+}
+
+int HTTPReactorServerSession::write(const char* buffer, std::streamsize length)
+{
+ try
+ {
+ return _realsocket.sendBytes(buffer, (int)length);
+ } catch (Poco::Exception& exc)
+ {
+ setException(exc);
+ throw;
+ }
+}
+
+}} // namespace Poco::Net
+
diff --git a/Net/src/HTTPServerRequestImpl.cpp b/Net/src/HTTPServerRequestImpl.cpp
index 9651a5dd5..4a686c29d 100644
--- a/Net/src/HTTPServerRequestImpl.cpp
+++ b/Net/src/HTTPServerRequestImpl.cpp
@@ -16,6 +16,7 @@
#include "Poco/Net/HTTPServerResponseImpl.h"
#include "Poco/Net/HTTPServerSession.h"
#include "Poco/Net/HTTPHeaderStream.h"
+#include "Poco/Net/HTTPSession.h"
#include "Poco/Net/HTTPStream.h"
#include "Poco/Net/HTTPFixedLengthStream.h"
#include "Poco/Net/HTTPChunkedStream.h"
@@ -31,7 +32,7 @@ namespace Poco {
namespace Net {
-HTTPServerRequestImpl::HTTPServerRequestImpl(HTTPServerResponseImpl& response, HTTPServerSession& session, HTTPServerParams* pParams):
+HTTPServerRequestImpl::HTTPServerRequestImpl(HTTPServerResponseImpl& response, HTTPSession& session, HTTPServerParams* pParams):
_response(response),
_session(session),
_pStream(0),
diff --git a/Net/src/HTTPServerResponseImpl.cpp b/Net/src/HTTPServerResponseImpl.cpp
index 7195dd7b0..ff033a565 100644
--- a/Net/src/HTTPServerResponseImpl.cpp
+++ b/Net/src/HTTPServerResponseImpl.cpp
@@ -16,6 +16,7 @@
#include "Poco/Net/HTTPServerRequestImpl.h"
#include "Poco/Net/HTTPServerSession.h"
#include "Poco/Net/HTTPHeaderStream.h"
+#include "Poco/Net/HTTPSession.h"
#include "Poco/Net/HTTPStream.h"
#include "Poco/Net/HTTPFixedLengthStream.h"
#include "Poco/Net/HTTPChunkedStream.h"
@@ -47,7 +48,7 @@ namespace Poco {
namespace Net {
-HTTPServerResponseImpl::HTTPServerResponseImpl(HTTPServerSession& session):
+HTTPServerResponseImpl::HTTPServerResponseImpl(HTTPSession& session):
_session(session),
_pRequest(0),
_pStream(0)
diff --git a/Net/src/TCPReactorAcceptor.cpp b/Net/src/TCPReactorAcceptor.cpp
new file mode 100644
index 000000000..71b8c86e6
--- /dev/null
+++ b/Net/src/TCPReactorAcceptor.cpp
@@ -0,0 +1,57 @@
+#include "Poco/Net/TCPReactorAcceptor.h"
+#include
+
+
+namespace Poco {
+namespace Net {
+
+
+TCPReactorAcceptor::TCPReactorAcceptor(
+ Poco::Net::ServerSocket& socket, Poco::Net::SocketReactor& reactor, TCPServerParams::Ptr pParams)
+ : Poco::Net::SocketAcceptor(socket, reactor), _pParams(pParams), _selfReactor(reactor),
+ _useSelfReactor(pParams->getUseSelfReactor())
+{
+ int workerThreads = _useSelfReactor ? 0 : _pParams->getMaxThreads();
+ if (workerThreads > 0)
+ {
+ _threadPool = std::make_shared("TCPRA", workerThreads, workerThreads);
+ }
+ for (int i = 0; i < workerThreads; i++)
+ {
+ std::shared_ptr workerReactor(std::make_shared());
+ _wokerReactors.push_back(workerReactor);
+ _threadPool->start(*workerReactor);
+ }
+}
+
+TCPReactorAcceptor::~TCPReactorAcceptor()
+{
+}
+
+SocketReactor& TCPReactorAcceptor::reactor()
+{
+ if (_useSelfReactor)
+ {
+ return _selfReactor;
+ }
+ static std::atomic_uint index(0);
+ return *_wokerReactors[index++ % _wokerReactors.size()];
+}
+
+TCPReactorServerConnection* TCPReactorAcceptor::createServiceHandler(Poco::Net::StreamSocket& socket)
+{
+ // enable nodelay per default: OSX really needs that
+#if defined(POCO_HAS_UNIX_SOCKET)
+ if (socket.address().family() != AddressFamily::UNIX_LOCAL)
+#endif
+ {
+ socket.setNoDelay(true);
+ }
+ auto tmpConnPtr = std::make_shared(socket, reactor());
+ tmpConnPtr->setRecvMessageCallback(_recvMessageCallback);
+ tmpConnPtr->initialize();
+ return tmpConnPtr.get();
+}
+
+}} // namespace Poco::Net
+
diff --git a/Net/src/TCPReactorServer.cpp b/Net/src/TCPReactorServer.cpp
new file mode 100644
index 000000000..e463680da
--- /dev/null
+++ b/Net/src/TCPReactorServer.cpp
@@ -0,0 +1,55 @@
+#include "Poco/Net/TCPReactorServer.h"
+#include "Poco/Net/ServerSocket.h"
+#include "Poco/Net/TCPServerParams.h"
+#include "Poco/ThreadPool.h"
+
+namespace Poco {
+namespace Net {
+
+
+
+TCPReactorServer::TCPReactorServer(int port, TCPServerParams::Ptr pParams)
+ : _threadPool("TCPR", pParams->getAcceptorNum()), _reactors(pParams->getAcceptorNum()), _port(port),
+ _pParams(pParams)
+{
+ for (auto& reactor : _reactors)
+ {
+ ServerSocket socket(_port);
+ _sockets.push_back(socket);
+ auto acceptor = std::make_shared(socket, reactor, _pParams);
+ _acceptors.push_back(acceptor);
+ }
+}
+
+TCPReactorServer::~TCPReactorServer()
+{
+ stop();
+}
+
+void TCPReactorServer::start()
+{
+ for (auto& reactor : _reactors)
+ {
+ _threadPool.start(reactor);
+ }
+}
+
+void TCPReactorServer::setRecvMessageCallback(const RecvMessageCallback& cb)
+{
+ for (auto& acceptor : _acceptors)
+ {
+ acceptor->setRecvMessageCallback(cb);
+ }
+}
+
+void TCPReactorServer::stop()
+{
+ for (auto& reactor : _reactors)
+ {
+ reactor.stop();
+ }
+ _threadPool.joinAll();
+}
+
+}} // namespace Poco::Net
+
diff --git a/Net/src/TCPReactorServerConnection.cpp b/Net/src/TCPReactorServerConnection.cpp
new file mode 100644
index 000000000..30228e1d7
--- /dev/null
+++ b/Net/src/TCPReactorServerConnection.cpp
@@ -0,0 +1,84 @@
+#include "Poco/Net/TCPReactorServerConnection.h"
+#include "Poco/Net/HTTPObserver.h"
+
+namespace Poco {
+namespace Net {
+
+
+const int BUFFER_SIZE = 4096;
+
+
+TCPReactorServerConnection::TCPReactorServerConnection(StreamSocket socket, SocketReactor& reactor)
+ : _reactor(reactor), _socket(socket)
+{
+ _buf.reserve(BUFFER_SIZE);
+}
+
+TCPReactorServerConnection::~TCPReactorServerConnection()
+{
+}
+
+void TCPReactorServerConnection::initialize()
+{
+ _reactor.addEventHandler(
+ _socket,
+ HTTPObserver(
+ shared_from_this(), &TCPReactorServerConnection::onRead));
+}
+
+void TCPReactorServerConnection::onRead(const AutoPtr& pNf)
+{
+ char tmp[BUFFER_SIZE] = {0};
+ int n = _socket.receiveBytes(tmp, sizeof(tmp));
+ if (n == 0)
+ {
+ handleClose();
+ } else if (n < 0)
+ {
+ // TODO
+ handleClose();
+ } else
+ {
+ _buf.append(tmp, n);
+ _rcvCallback(shared_from_this());
+ }
+}
+
+void TCPReactorServerConnection::onError(const AutoPtr& pNf)
+{
+ handleClose();
+}
+
+void TCPReactorServerConnection::onShutdown(const AutoPtr& pNf)
+{
+ handleClose();
+}
+
+void TCPReactorServerConnection::handleClose()
+{
+ // here must keep _socket to delay the _socket destrcutor
+ StreamSocket keepSocket = _socket;
+ // here will delete this, so memberships' destructor will be invoked
+ _reactor.removeEventHandler(
+ _socket,
+ HTTPObserver(
+ shared_from_this(), &TCPReactorServerConnection::onRead));
+}
+
+const StreamSocket& TCPReactorServerConnection::socket()
+{
+ return _socket;
+}
+
+std::string& TCPReactorServerConnection::buffer()
+{
+ return _buf;
+}
+
+void TCPReactorServerConnection::setRecvMessageCallback(const RecvMessageCallback& cb)
+{
+ _rcvCallback = cb;
+}
+
+}} // namespace Poco::Net
+
diff --git a/Net/src/TCPServerParams.cpp b/Net/src/TCPServerParams.cpp
index 6a90374ab..c50d1c0b1 100644
--- a/Net/src/TCPServerParams.cpp
+++ b/Net/src/TCPServerParams.cpp
@@ -13,6 +13,7 @@
#include "Poco/Net/TCPServerParams.h"
+#include "Poco/Bugcheck.h"
namespace Poco {
@@ -23,7 +24,10 @@ TCPServerParams::TCPServerParams():
_threadIdleTime(10000000),
_maxThreads(0),
_maxQueued(64),
- _threadPriority(Poco::Thread::PRIO_NORMAL)
+ _threadPriority(Poco::Thread::PRIO_NORMAL),
+ _reactorMode(false),
+ _acceptorNum(1),
+ _useSelfReactor(false)
{
}
@@ -60,5 +64,35 @@ void TCPServerParams::setThreadPriority(Poco::Thread::Priority prio)
_threadPriority = prio;
}
+bool TCPServerParams::getReactorMode() const
+{
+ return _reactorMode;
+}
+void TCPServerParams::setReactorMode(bool reactorMode)
+{
+ _reactorMode = reactorMode;
+}
+int TCPServerParams::getAcceptorNum() const
+{
+ poco_assert(_reactorMode);
+ return _acceptorNum;
+}
+void TCPServerParams::setAcceptorNum(int acceptorNum)
+{
+ poco_assert(_reactorMode);
+ poco_assert(acceptorNum > 0);
+ _acceptorNum = acceptorNum;
+}
+bool TCPServerParams::getUseSelfReactor() const
+{
+ poco_assert(_reactorMode);
+ return _useSelfReactor;
+}
+void TCPServerParams::setUseSelfReactor(bool useSelfReactor)
+{
+ poco_assert(_reactorMode);
+ _useSelfReactor = useSelfReactor;
+}
+
} } // namespace Poco::Net
diff --git a/Net/testsuite/Makefile b/Net/testsuite/Makefile
index 0070233e9..845a128e0 100644
--- a/Net/testsuite/Makefile
+++ b/Net/testsuite/Makefile
@@ -15,6 +15,7 @@ objects = \
HTTPRequestTest MessageHeaderTest NetTestSuite UDPEchoServer \
HTTPResponseTest MessagesTestSuite NetworkInterfaceTest \
HTTPServerTest MulticastEchoServer SocketAddressTest \
+ HTTPReactorServerSessionTest HTTPReactorServerTestSuite \
HTTPCookieTest HTTPCredentialsTest HTMLFormTest HTMLTestSuite \
MediaTypeTest QuotedPrintableTest DialogSocketTest \
HTTPClientTestSuite FTPClientTestSuite FTPClientSessionTest \
diff --git a/Net/testsuite/TestSuite_vs170.vcxproj b/Net/testsuite/TestSuite_vs170.vcxproj
index 03051fa8a..a00cad876 100644
--- a/Net/testsuite/TestSuite_vs170.vcxproj
+++ b/Net/testsuite/TestSuite_vs170.vcxproj
@@ -978,6 +978,8 @@
+
+
@@ -1110,6 +1112,16 @@
stdcpp17
stdc11