feat(socket): implement callbacks for asynchronous handling of requests and responses
This commit is contained in:
parent
0887acd81a
commit
e1be8d8aa8
@ -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
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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());
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -68,4 +68,17 @@ int ASocket::getFd() const
|
|||||||
void ASocket::setFd(int fd)
|
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);
|
||||||
|
}
|
||||||
|
|||||||
@ -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>
|
||||||
|
|
||||||
@ -27,6 +29,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;
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user