Commit 29ff10ff authored by Mathieu Stefani's avatar Mathieu Stefani

Add a unit-test to make sure server will raise an HTTP 408 Request-Timeout...

Add a unit-test to make sure server will raise an HTTP 408 Request-Timeout when hitting a timeout before receiving client headers
parent 6d38ea58
......@@ -11,6 +11,8 @@
#include <future>
#include <string>
#include "tcp_client.h"
using namespace Pistache;
struct HelloHandlerWithDelay : public Http::Handler {
......@@ -86,6 +88,22 @@ struct AddressEchoHandler : public Http::Handler {
}
};
struct PingHandler : public Http::Handler {
HTTP_PROTOTYPE(PingHandler)
PingHandler() = default;
void onRequest(const Http::Request& request,
Http::ResponseWriter writer) override {
if (request.resource() == "/ping") {
writer.send(Http::Code::Ok, "PONG");
}
else {
writer.send(Http::Code::Not_Found);
}
}
};
int clientLogicFunc(int response_size, const std::string &server_page,
int timeout_seconds, int wait_seconds) {
Http::Client client;
......@@ -414,3 +432,32 @@ TEST(http_server_test, response_size_captured) {
ASSERT_LT(rsize, 300u);
ASSERT_EQ(rcode, Http::Code::Ok);
}
TEST(http_server_test, client_request_header_timeout_raises_http_408) {
Pistache::Address address("localhost", Pistache::Port(0));
Http::Endpoint server(address);
auto flags = Tcp::Options::ReuseAddr;
auto opts = Http::Endpoint::options().flags(flags);
server.init(opts);
server.setHandler(Http::make_handler<PingHandler>());
server.serveThreaded();
auto port = server.getPort();
auto addr = "localhost:" + port.toString();
std::cout << "Server address: " << addr << "\n";
std::string reqStr = "GET /ping HTTP/1.1\r\n";
char recvBuf[1024];
std::memset(recvBuf, 0, sizeof(recvBuf));
size_t bytes;
TcpClient client;
EXPECT_TRUE(client.connect(Pistache::Address("localhost", port))) << client.lastError();
EXPECT_TRUE(client.send(reqStr)) << client.lastError();
EXPECT_TRUE(client.receive(recvBuf, sizeof(recvBuf), &bytes, std::chrono::seconds(5))) << client.lastError();
server.shutdown();
}
#pragma once
#include <pistache/net.h>
#include <pistache/os.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <poll.h>
namespace Pistache
{
#define CLIENT_TRY(...) \
do { \
auto ret = __VA_ARGS__; \
if (ret < 0) { \
lastError_ = strerror(errno); \
return false; \
} \
} while (0) \
class TcpClient
{
public:
bool connect(const Pistache::Address& address)
{
struct addrinfo hints;
std::memset(&hints, 0, sizeof(hints));
hints.ai_family = address.family();
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = 0;
hints.ai_protocol = 0;
auto host = address.host();
auto port = address.port().toString();
AddrInfo addrInfo;
CLIENT_TRY(addrInfo.invoke(host.c_str(), port.c_str(), &hints));
const auto* addrs = addrInfo.get_info_ptr();
int sfd = -1;
auto* addr = addrs;
for (; addr; addr = addr->ai_next) {
sfd = ::socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if (sfd < 0)
continue;
break;
}
CLIENT_TRY(sfd);
CLIENT_TRY(::connect(sfd, addr->ai_addr, addr->ai_addrlen));
make_non_blocking(sfd);
fd_ = sfd;
return true;
}
bool send(const std::string& data)
{
return send(data.c_str(), data.size());
}
bool send(const void* data, size_t size)
{
CLIENT_TRY(::send(fd_, data, size, 0));
return true;
}
template<typename Duration>
bool receive(void* buffer, size_t size, size_t *bytes, Duration timeout)
{
struct pollfd fds[1];
fds[0].fd = fd_;
fds[0].events = POLLIN;
auto timeoutMs = std::chrono::duration_cast<std::chrono::milliseconds>(timeout);
auto ret = ::poll(fds, 1, static_cast<int>(timeoutMs.count()));
if (ret < 0)
{
lastError_ = strerror(errno);
return false;
}
if (ret == 0)
{
lastError_ = "Poll timeout";
return false;
}
if (fds[0].revents & POLLERR)
{
lastError_ = "An error has occured on the stream";
return false;
}
auto res = ::recv(fd_, buffer, size, 0);
if (res < 0)
{
lastError_ = strerror(errno);
return false;
}
*bytes = static_cast<size_t>(res);
return true;
}
std::string lastError() const
{
return lastError_;
}
private:
int fd_;
std::string lastError_;
};
#undef CLIENT_TRY
} // namespace Pistache
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment