feat(socket): implement callbacks for asynchronous handling of requests and responses

This commit is contained in:
Quinten 2025-10-15 17:29:22 +02:00
parent 0887acd81a
commit e1be8d8aa8
6 changed files with 61 additions and 24 deletions

View File

@ -1,3 +1,4 @@
#include "webserv/socket/ASocket.hpp"
#include "webserv/socket/CgiSocket.hpp" #include "webserv/socket/CgiSocket.hpp"
#include <webserv/client/Client.hpp> #include <webserv/client/Client.hpp>
@ -24,6 +25,7 @@ Client::Client(std::unique_ptr<ClientSocket> socket, Server &server)
{ {
Log::trace(LOCATION); Log::trace(LOCATION);
Log::info("New client connected, fd: " + std::to_string(client_socket_->getFd())); Log::info("New client connected, fd: " + std::to_string(client_socket_->getFd()));
client_socket_->setCallback([this]() { request(); });
} }
Client::~Client() Client::~Client()
@ -43,6 +45,20 @@ void Client::setStatusCode(int code)
statusCode_ = code; statusCode_ = code;
} }
ASocket &Client::getSocket(int fd) const
{
if (fd == -1 || client_socket_->getFd() == fd)
{
return *client_socket_;
}
if (cgi_socket_ && cgi_socket_->getFd() == fd)
{
return *client_socket_; // TODO return cgi socket
}
Log::error("Socket not found for fd: " + std::to_string(fd));
throw std::runtime_error("Socket not found for fd: " + std::to_string(fd));
}
void Client::request() void Client::request()
{ {
Log::trace(LOCATION); Log::trace(LOCATION);
@ -101,14 +117,23 @@ void Client::poll() const
if (httpResponse_->isComplete()) if (httpResponse_->isComplete())
{ {
Log::info("Response is ready to be sent to client, fd: " + std::to_string(client_socket_->getFd())); Log::info("Response is ready to be sent to client, fd: " + std::to_string(client_socket_->getFd()));
client_socket_->setCallback([this]() { respond(); });
server_.responseReady(client_socket_->getFd()); server_.responseReady(client_socket_->getFd());
} }
} }
std::vector<uint8_t> Client::getResponse() const void Client::respond() const
{ {
auto payload = httpResponse_->toBytes();
return httpResponse_->toBytes(); ssize_t bytesSent = send(client_socket_->getFd(), payload.data(), payload.size(), 0);
if (bytesSent < 0)
{
Log::error("Send failed for fd: " + std::to_string(client_socket_->getFd()));
}
else
{
Log::debug("Sent " + std::to_string(bytesSent) + " bytes to fd: " + std::to_string(client_socket_->getFd()));
}
} }
HttpRequest &Client::getHttpRequest() const HttpRequest &Client::getHttpRequest() const

View File

@ -35,12 +35,12 @@ class Client
~Client(); ~Client();
void request(); void request();
void respond() const;
void poll() const; void poll() const;
[[nodiscard]] std::vector<uint8_t> getResponse() const;
[[nodiscard]] int getStatusCode() const; [[nodiscard]] int getStatusCode() const;
[[nodiscard]] ClientSocket &getSocket() const { return *client_socket_; } [[nodiscard]] ASocket &getSocket(int fd = -1) const;
void setStatusCode(int code); void setStatusCode(int code);
void setCgiSocket(std::unique_ptr<CgiSocket> cgiSocket); void setCgiSocket(std::unique_ptr<CgiSocket> cgiSocket);

View File

@ -156,16 +156,16 @@ bool URI::isCgi() const
std::string URI::getCgiPath() const std::string URI::getCgiPath() const
{ {
Log::debug("BaseName: " + baseName_ + ", FullPath: " + fullPath_ + ", Dir: " + dir_ + ", PathInfo: " + pathInfo_ + // Log::debug("BaseName: " + baseName_ + ", FullPath: " + fullPath_ + ", Dir: " + dir_ + ", PathInfo: " + pathInfo_ +
", Extension: " + getExtension()); // ", Extension: " + getExtension());
if (!isFile() || getExtension().empty() || !config_->get<bool>("cgi_enabled").has_value() if (!isFile() || getExtension().empty() || !config_->get<bool>("cgi_enabled").has_value()
|| !config_->get<bool>("cgi_enabled").value()) || !config_->get<bool>("cgi_enabled").value())
{ {
Log::debug("CGI not enabled or not a file or no extension", // Log::debug("CGI not enabled or not a file or no extension",
{{"isFile", isFile() ? "true" : "false"}, // {{"isFile", isFile() ? "true" : "false"},
{"extension", getExtension()}, // {"extension", getExtension()},
{"cgi_enabled", config_->get<bool>("cgi_enabled").has_value() ? "true" : "false"}, // {"cgi_enabled", config_->get<bool>("cgi_enabled").has_value() ? "true" : "false"},
{"cgi_enabled_value", config_->get<bool>("cgi_enabled").value() ? "true" : "false"}}); // {"cgi_enabled_value", config_->get<bool>("cgi_enabled").value() ? "true" : "false"}});
return ""; return "";
} }
auto cgiPath = config_->getCGIPath(getExtension()); auto cgiPath = config_->getCGIPath(getExtension());

View File

@ -163,8 +163,10 @@ void Server::handleRequest(struct epoll_event *event) const
Log::trace(LOCATION); Log::trace(LOCATION);
int client_fd = event->data.fd; int client_fd = event->data.fd;
Client &client = getClient(client_fd); Client &client = getClient(client_fd);
client.request(); client.getSocket().callback();
} }
void Server::responseReady(int client_fd) const void Server::responseReady(int client_fd) const
@ -185,16 +187,7 @@ void Server::handleResponse(struct epoll_event *event)
{ {
Log::debug("Attempting to send data to fd: " + std::to_string(event->data.fd)); Log::debug("Attempting to send data to fd: " + std::to_string(event->data.fd));
Client &client = getClient(event->data.fd); Client &client = getClient(event->data.fd);
auto payload = client.getResponse(); client.getSocket().callback();
ssize_t bytesSent = send(event->data.fd, payload.data(), payload.size(), 0);
if (bytesSent < 0)
{
Log::error("Send failed for fd: " + std::to_string(event->data.fd) + " with error: " + std::strerror(errno));
}
else
{
Log::debug("Sent " + std::to_string(bytesSent) + " bytes to fd: " + std::to_string(event->data.fd));
}
disconnect(client); disconnect(client);
} }

View File

@ -69,3 +69,16 @@ void ASocket::setFd(int fd)
{ {
fd_ = fd; fd_ = fd;
} }
void ASocket::callback() const
{
if (callback_ != nullptr)
{
callback_();
}
}
void ASocket::setCallback(std::function<void()> callback)
{
callback_ = std::move(callback);
}

View File

@ -1,5 +1,7 @@
#pragma once #pragma once
#include <functional> // for function
#include <cstddef> // for size_t #include <cstddef> // for size_t
#include <cstdint> #include <cstdint>
@ -28,6 +30,9 @@ class ASocket
[[nodiscard]] virtual Type getType() const = 0; [[nodiscard]] virtual Type getType() const = 0;
[[nodiscard]] int getFd() const; [[nodiscard]] int getFd() const;
void callback() const;
void setCallback(std::function<void()> callback);
ssize_t read(void *buf, size_t len) const; ssize_t read(void *buf, size_t len) const;
ssize_t write(const void *buf, size_t len) const; ssize_t write(const void *buf, size_t len) const;
@ -37,4 +42,5 @@ class ASocket
private: private:
int fd_; int fd_;
std::function<void()> callback_ = nullptr;
}; };