Implemented the recieving part of HttpRequest

and changed client to use HttpRequest
This commit is contained in:
whaffman 2025-09-22 21:49:38 +02:00
parent 6766bd8744
commit 3dc12fab9d
4 changed files with 189 additions and 52 deletions

View File

@ -6,8 +6,10 @@
#include <iostream> #include <iostream>
Client::Client(std::unique_ptr<Socket> socket, Server &server, const ServerConfig &server_config) Client::Client(std::unique_ptr<Socket> socket, Server &server, const ServerConfig &server_config)
: client_socket_(std::move(socket)), server_(std::ref(server)), server_config_(std::cref(server_config)) : client_socket_(std::move(socket)), server_(std::ref(server)), server_config_(std::cref(server_config)),
httpRequest_(std::make_unique<HttpRequest>(&server_config, this))
{ {
} }
Client::~Client() Client::~Client()
@ -16,23 +18,6 @@ Client::~Client()
server_.removeFromEpoll(*client_socket_); server_.removeFromEpoll(*client_socket_);
}; };
int Client::parseHeaderforContentLength(const std::string &request) // NOLINT
{
std::string header = "Content-Length: ";
size_t pos = request.find(header);
Log::debug("Parsing header for Content-Length...\n" + header);
if (pos != std::string::npos)
{
size_t start = pos + header.length();
size_t end = request.find("\r\n", start);
if (end != std::string::npos)
{
std::string lengthStr = request.substr(start, end - start);
return std::atoi(lengthStr.c_str());
}
}
return -1; // Not found
}
void Client::request() void Client::request()
{ {
@ -51,33 +36,15 @@ void Client::request()
} }
buffer[bytesRead] = '\0'; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) buffer[bytesRead] = '\0'; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index)
requestBuffer_ += buffer; // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay) httpRequest_->receiveData(buffer, static_cast<size_t>(bytesRead));
if (header_.empty())
{ if(httpRequest_->getState() == HttpRequest::State::Complete) {
auto headerEnd = requestBuffer_.find("\r\n\r\n"); Log::info("Received complete request:\n" + httpRequest_->getHeaders() + httpRequest_->getBody() + "\n=== FULL REQUEST FINISHED\n");
if (headerEnd != std::string::npos) server_.responseReady(client_socket_->getFd());
{ httpRequest_->reset();
header_ = requestBuffer_.substr(0, headerEnd + 4);
contentLength_ = parseHeaderforContentLength(header_);
if (contentLength_ == -1)
{
Log::info("Received complete request:\n" + requestBuffer_ + "\n=== HEADER FINISHED\n");
server_.responseReady(client_socket_->getFd());
}
requestBuffer_.erase(0, headerEnd + 4);
return;
}
} }
else else {
{ Log::debug("Received partial request:\n" + httpRequest_->getHeaders() + httpRequest_->getBody() + "\n=== PARTIAL REQUEST\n");
content_ += requestBuffer_;
if (content_.size() >= contentLength_)
{
Log::info("Received complete request:\n" + header_ + content_ + "\n=== FULL REQUEST FINISHED\n");
server_.responseReady(client_socket_->getFd());
requestBuffer_.clear();
contentLength_ = -1;
}
} }
} }

View File

@ -4,7 +4,7 @@
#include <webserv/config/ServerConfig.hpp> #include <webserv/config/ServerConfig.hpp>
#include <webserv/server/Server.hpp> #include <webserv/server/Server.hpp>
#include <webserv/http/HttpRequest.hpp>
#include <memory> #include <memory>
class Server; class Server;
@ -25,11 +25,12 @@ class Client
[[nodiscard]] std::string getResponse() const; [[nodiscard]] std::string getResponse() const;
private: private:
std::unique_ptr<HttpRequest> httpRequest_ = nullptr;
int parseHeaderforContentLength(const std::string &request); int parseHeaderforContentLength(const std::string &request);
int contentLength_{-1}; // int contentLength_{-1};
std::string requestBuffer_; // std::string requestBuffer_;
std::string header_; // std::string header_;
std::string content_; // std::string content_;
std::unique_ptr<Socket> client_socket_; std::unique_ptr<Socket> client_socket_;
const Server &server_; const Server &server_;
const ServerConfig &server_config_; const ServerConfig &server_config_;

View File

@ -1,5 +1,130 @@
#include <webserv/http/HttpRequest.hpp> #include <webserv/http/HttpRequest.hpp>
#include <webserv/log/Log.hpp>
HttpRequest::HttpRequest() HttpRequest::HttpRequest(const ServerConfig *serverConfig, const Client *client)
: serverConfig_(serverConfig), client_(client)
{ {
Log::trace("HttpRequest constructor called");
}
HttpRequest::~HttpRequest()
{
Log::trace("HttpRequest destructor called");
}
HttpRequest::State HttpRequest::getState() const
{
Log::trace("HttpRequest::getState() called");
return state_;
}
const std::string &HttpRequest::getHeaders() const
{
return headers_;
}
const std::string &HttpRequest::getBody() const
{
return body_;
}
size_t HttpRequest::getContentLength() const
{
return contentLength_;
}
void HttpRequest::receiveData(const char *data, size_t length)
{
Log::trace("HttpRequest::receiveData() called");
buffer_.append(data, length);
parseBuffer();
}
void HttpRequest::parseContentLength()
{
// Parse headers to find Content-Length
size_t pos = headers_.find("Content-Length:");
if (pos != std::string::npos)
{
pos += 15;
while (pos < headers_.size() && (headers_[pos] == ' ' || headers_[pos] == '\t'))
{
++pos; // Skip whitespace
}
size_t endPos = headers_.find("\r\n", pos);
std::string contentLengthValue = headers_.substr(pos, endPos - pos);
contentLength_ = std::stoul(contentLengthValue);
}
else
{
contentLength_ = 0; // No body expected
}
}
void HttpRequest::parseBuffer()
{
while (true)
{
if (state_ == State::RequestLine)
{
size_t pos = buffer_.find("\r\n");
if (pos == std::string::npos)
{
Log::debug("HttpRequest::parseBuffer() in state RequestLine waiting for more data");
return; // Wait for more data
}
requestLine_ = buffer_.substr(0, pos);
buffer_.erase(0, pos + 2);
state_ = State::Headers;
}
else if (state_ == State::Headers)
{
size_t pos = buffer_.find("\r\n\r\n");
if (pos == std::string::npos)
{
Log::debug("HttpRequest::parseBuffer() in state Headers waiting for more data");
return; // Wait for more data
}
headers_ = buffer_.substr(0, pos + 2); // Include the last \r\n
buffer_.erase(0, pos + 4);
parseContentLength();
if (contentLength_ > 0)
{
state_ = State::Body;
}
else
{
Log::debug("HttpRequest::parseBuffer() in state Headers no body to read");
state_ = State::Complete;
return; // No body to read
}
}
else if (state_ == State::Body)
{
if (buffer_.size() < contentLength_)
{
Log::debug("HttpRequest::parseBuffer() in state Body waiting for more data");
return; // Wait for more data
}
body_ = buffer_.substr(0, contentLength_);
buffer_.erase(0, contentLength_);
state_ = State::Complete;
}
else if (state_ == State::Complete)
{
Log::debug("HttpRequest::parseBuffer() request is complete");
return; // Request is complete
}
}
}
void HttpRequest::reset()
{
Log::trace("HttpRequest::reset() called");
state_ = State::RequestLine;
buffer_.clear();
requestLine_.clear();
headers_.clear();
body_.clear();
contentLength_ = 0;
} }

View File

@ -1,7 +1,51 @@
#pragma once #pragma once
#include "webserv/config/ServerConfig.hpp"
#include <cstddef>
#include <cstdint>
#include <string>
class Client;
class HttpRequest class HttpRequest
{ {
public: public:
HttpRequest(); enum class State : std::uint8_t
{
RequestLine,
Headers,
Body,
Complete
};
HttpRequest(const ServerConfig *serverConfig, const Client *client);
HttpRequest(const HttpRequest &other) = delete;
HttpRequest(HttpRequest &&other) noexcept = delete;
HttpRequest &operator=(const HttpRequest &other) = delete;
HttpRequest &operator=(HttpRequest &&other) noexcept = delete;
~HttpRequest();
[[nodiscard]] State getState() const;
[[nodiscard]] const std::string &getHeaders() const;
[[nodiscard]] const std::string &getBody() const;
[[nodiscard]] size_t getContentLength() const;
void receiveData(const char *data, size_t length);
void reset();
private:
void parseBuffer();
void parseContentLength();
const ServerConfig *serverConfig_;
const Client *client_;
State state_ = State::RequestLine;
std::string buffer_;
std::string requestLine_;
std::string headers_;
std::string body_;
size_t contentLength_ = 0;
}; };