You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
There is no way to interrupt a http request if there is no response from the other side. The connection succeeds but if the other side doesn't send any response, the requests becomes stalled - the receiveResponse() call will block forever. It is even not possible to interrupt it with session methods abort() or reset(), see the example below.
To Reproduce
Start a local fake web server using net-cat, e.g. nc 127.0.0.1 8000 (it will not send anything in response)
Run a program below which opens a connection to 127.0.0.1:8000 and sends a GET request
Expected behavior
There should be some internal timeout working. Method setTimeout() ensures a timeout is triggered if the connection cannot be established within the time span but once the connection is established it is waiting for the response status code and message. If no response arrives the timeout is not triggered. Even if I try to handle the timeout manually (as in the example below) it is not possible to abort it using any session method available.
I may be missing something, please advise.
Example
#include "Poco/StreamCopier.h"
#include "Poco/URI.h"
#include "Poco/Net/HTTPStreamFactory.h"
#include "Poco/Net/NetException.h"
#include <Poco/Net/HTTPClientSession.h>
#include <Poco/Net/HTTPRequest.h>
#include <Poco/Net/HTTPResponse.h>
#include "Poco/Stopwatch.h"
#include <iostream>
#include <chrono>
#include <thread>
#include <future>
#include <atomic>
#include <condition_variable>
int main(int argc, char** argv)
{
Poco::Net::HTTPStreamFactory::registerFactory();
// timeoute monitoring
std::condition_variable cv;
std::mutex cvLock;
std::atomic<bool> fullResponseRead = false;
// set timeout to 3 seconds
Poco::UInt64 timeout = 3 * 1000000L; // in microseconds
const Poco::Timespan ts(timeout, 0L);
// stop watch to measure total time
Poco::Stopwatch stopWatch;
stopWatch.start();
// read buffer
std::string readBuffer;
std::future<void> handleStreamTimeout;
// session
Poco::URI requestUri("http://127.0.0.1:8000");
Poco::Net::HTTPClientSession httpSession;
httpSession.setHost(requestUri.getHost());
if (requestUri.getPort() > 0) {
httpSession.setPort(requestUri.getPort());
}
// request
Poco::Net::HTTPRequest httpRequest(Poco::Net::HTTPRequest::HTTP_GET, requestUri.getPathAndQuery(), Poco::Net::HTTPMessage::HTTP_1_0);
Poco::Net::HTTPResponse httpResponse;
try {
readBuffer.clear();
fullResponseRead = false;
httpSession.setKeepAlive(false);
httpSession.setTimeout(ts);
std::cout << " ---------- SEND request -------- " << std::endl;
httpSession.sendRequest(httpRequest);
std::cout << " ---------- SENT -------- " << std::endl;
// for POCO++ 1.13 use httpSession.setReceiveTimeout(ts) instead
Poco::Net::StreamSocket &str = httpSession.socket();
str.setReceiveTimeout(ts);
std::cout << " ---------- PREPARING TIMEOUT HANDLER -------- " << std::endl;
std::future<void> handleStreamTimeout = std::async(
std::launch::async,
[&httpSession, &fullResponseRead, &stopWatch, &timeout, &cv, &cvLock]() -> void {
auto lock = std::unique_lock<std::mutex>(cvLock);
Poco::UInt64 elapsed = stopWatch.elapsed();
while (!fullResponseRead.load() && timeout > elapsed) {
cv.wait_until(lock, std::chrono::system_clock::now() + std::chrono::microseconds(timeout - elapsed));
std::cout << "------- TIMEOUT WAKEUP" << std::endl;
if (fullResponseRead.load()) {
// we are notified that the response was successfully read
break;
}
elapsed = stopWatch.elapsed();
}
// timed out
// these are attempts to abort the session, none of them works
std::cout << "------- TIMEOUT reset" << std::endl;
httpSession.reset();
std::cout << "------- TIMEOUT socket close" << std::endl;
httpSession.socket().close();
std::cout << "------- TIMEOUT abort" << std::endl;
httpSession.abort();
std::cout << "------- TIMEOUT end " << elapsed << std::endl;
}
);
std::cout << " ---------- WAITING -------- " << std::endl;
std::istream& httpResponseStream = httpSession.receiveResponse(httpResponse);
std::cout << " ---------- REPORTING -------- " << std::endl;
std::cout << "Status: " << httpResponse.getStatus()
<< std::endl << "Reason: " << httpResponse.getReason()
<< std::endl;
// copy response to a string
std::cout << " ---------- COPYING -------- " << std::endl;
Poco::StreamCopier::copyToString(httpResponseStream, readBuffer, 1);
// stop the timeout timer
{
std::lock_guard<std::mutex> lock(cvLock);
fullResponseRead = true;
cv.notify_all();
}
// wait for the timeout timer job to finish
handleStreamTimeout.get();
std::cout << " ---------- FINISHED -------- " << std::endl;
} catch (Poco::TimeoutException const &ex) {
std::cout << "Timed out: " << ex.displayText() << std::endl;
} catch (Poco::Net::NetException const &ex) {
std::cout << "Network exception " << ex.displayText() << std::endl;
} catch (...) {
// just in case we get unexpected exception
std::exception_ptr pe = std::current_exception();
std::cout << "Unknown exception " << (pe ? pe.__cxa_exception_type()->name() : "null") << std::endl;
}
// wait for the timeout job to finish (if not finished due to an exception)
stopWatch.stop();
if (handleStreamTimeout.valid()) {
std::lock_guard<std::mutex> lock(cvLock);
// let the timer know it can stop, wait for it to finish
fullResponseRead = true;
cv.notify_all();
handleStreamTimeout.get(); // finish the thread
}
std::cout << " ---------- DONE -------- " << std::endl;
std::cout << readBuffer << std::endl;
}
As you can see, none of the attempts to abort the session works, call to abort() even blocks forever (TIMEOUT END) is not reached at all. If I interrupt nc it also triggers network exception in the client with message No message received.
Environment information:
OS Type and Version: Ubuntu 24.4,
POCO Version: 1.11.0-4 (system)
g++ compiler: 13.2.0
The text was updated successfully, but these errors were encountered:
There is no way to interrupt a http request if there is no response from the other side. The connection succeeds but if the other side doesn't send any response, the requests becomes stalled - the
receiveResponse()
call will block forever. It is even not possible to interrupt it with session methodsabort()
orreset()
, see the example below.To Reproduce
nc 127.0.0.1 8000
(it will not send anything in response)Expected behavior
There should be some internal timeout working. Method
setTimeout()
ensures a timeout is triggered if the connection cannot be established within the time span but once the connection is established it is waiting for the response status code and message. If no response arrives the timeout is not triggered. Even if I try to handle the timeout manually (as in the example below) it is not possible to abort it using any session method available.I may be missing something, please advise.
Example
Compile with
The output is:
As you can see, none of the attempts to abort the session works, call to
abort()
even blocks forever (TIMEOUT END) is not reached at all. If I interruptnc
it also triggers network exception in the client with messageNo message received
.Environment information:
The text was updated successfully, but these errors were encountered: