I have an http server and I want to be able to drop connections and request handlers after a certain timeout. For example: I have a handler with some logic and this logic could hang for 60 seconds, in this case I don't want my server and clients wait this long for this handler to finish and would prefer dropping it if logic takes longer than 10 seconds to execute.
Initially I thought I could set a global timeout for all connections via setting setTimeout(tsp) on HTTPServerParams and passing them to HttpServer during it's creation, but it doesn't seem to work and my request handler definitely could run longer than the timeout I set.
Later I found that I could access HTTPServerSession and call abort() on it, so theoretically I could implement such "dropping" by having a timer in another thread that will keep track of pointers to all the sessions and their execution times and aborting them after the specified timeout. But I'm not sure if this is idiomatic way of using it and if it could cause any issues in the long run.
So I have few questions:
- Is there such mechanism in Poco that I'm not aware of?
- Is it possible to implement it via
abort()and what are the implications? Maybe this method was never intended to be used by me, library consumer, and is only intended to be used internally in Poco. - What does
setTimeoutactually control? Maybe I misunderstood the documentation.
I have a code example, you could just send an arbitrary request to this server (I can provide a cmakefile and conanfile for easily building this if anyone interested in running it themselves):
#include <Poco/Net/HTTPRequestHandlerFactory.h>
#include <Poco/Net/HTTPRequestHandler.h>
#include <Poco/Net/HTTPServer.h>
#include <Poco/Net/HTTPServerParams.h>
#include <Poco/Net/HTTPServerRequest.h>
#include <Poco/Net/HTTPServerRequestImpl.h>
#include <Poco/Net/HTTPServerResponse.h>
#include <Poco/Net/HTTPServerSession.h>
#include <Poco/Net/ServerSocket.h>
#include <Poco/Net/SocketAddress.h>
#include <Poco/Util/ServerApplication.h>
#include <Poco/Timespan.h>
#include <iostream>
#include <chrono>
#include <thread>
class RequestHandler : public Poco::Net::HTTPRequestHandler
{
protected:
void handleRequest(
Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response) final;
};
void RequestHandler::handleRequest(
Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response)
{
std::cout << "Started handling the request" << std::endl;
// I can drop the handler with this, what are the comlications?
// Poco::Net::HTTPServerRequestImpl& requestImpl =
// static_cast<Poco::Net::HTTPServerRequestImpl&>(request);
// requestImpl.session().abort();
std::this_thread::sleep_for(std::chrono::seconds{ 60 });
std::cout << "Finished handling the request" << std::endl;
response.setStatus(Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK);
response.send() << "OK";
}
class RequestRouter : public Poco::Net::HTTPRequestHandlerFactory
{
public:
Poco::Net::HTTPRequestHandler* createRequestHandler(
const Poco::Net::HTTPServerRequest& request) override;
};
Poco::Net::HTTPRequestHandler* RequestRouter::createRequestHandler(
const Poco::Net::HTTPServerRequest&)
{
return new RequestHandler{};
}
class App : public Poco::Util::ServerApplication
{
public:
App() = default;
int main(const std::vector<std::string>&) override;
};
int App::main(const std::vector<std::string>&)
{
Poco::Timespan tsp{ std::chrono::seconds{ 10 } };
auto socket{ std::make_unique<Poco::Net::ServerSocket>(
Poco::Net::SocketAddress{ Poco::Net::IPAddress{ "0.0.0.0" }, 8000 }) };
auto params = new Poco::Net::HTTPServerParams{};
params->setKeepAlive(true);
params->setMaxKeepAliveRequests(100);
params->setMaxQueued(100);
params->setMaxThreads(10);
params->setKeepAliveTimeout(tsp);
params->setTimeout(tsp);
auto server{ std::make_unique<Poco::Net::HTTPServer>(new RequestRouter{}, *socket, params) };
server->start();
waitForTerminationRequest();
server->stopAll();
return 0;
}
POCO_SERVER_MAIN(App)