refactor(ServerConfig): update directive parsing and improve server socket binding

This commit is contained in:
Quinten 2025-09-25 17:51:37 +02:00
parent c9e74ca508
commit 1e80839864
5 changed files with 132 additions and 94 deletions

View File

@ -80,7 +80,7 @@ std::string Client::getResponse() const
}
// further validation can be added here
response += "Content-Length: 18\r\n\r\n";
response += "Server port " + std::to_string(server_config_.getPort()) + "\r\n";
response += "Server port 8080\r\n";
Log::debug("Sending response:\n" + response);
return response;

View File

@ -2,6 +2,9 @@
#include <webserv/config/ServerConfig.hpp>
#include <webserv/config/utils.hpp> // for findCorrespondingClosingBrace, trim
#include <webserv/log/Log.hpp> // for Log, LOCATION
#include <webserv/config/directive/DirectiveFactory.hpp> // for DirectiveFactory
#include <webserv/config/directive/ADirective.hpp> // for ADirective
#include <cstddef> // for size_t
#include <sstream> // for basic_istringstream, basic_istream, istringstream
@ -54,92 +57,123 @@ void ServerConfig::parseServerBlock(const std::string &block)
parseDirectives(serverDeclarations);
}
// void ServerConfig::parseDirectives(const std::string &declarations)
// {
// Log::info("Parsing server directives");
// std::string line;
// std::istringstream stream(declarations);
// while (std::getline(stream, line))
// {
// std::string directive;
// std::istringstream lineStream{line};
// lineStream >> directive;
// if (!directive.empty())
// {
// std::string value;
// lineStream >> value;
// if (directive == "listen")
// {
// port_ = std::stoi(value);
// if (port_ < 1 || port_ > 65535)
// {
// throw std::runtime_error("Invalid port number: " + std::to_string(port_));
// }
// Log::debug("Set port to " + std::to_string(port_));
// }
// else if (directive == "root")
// {
// root_ = value;
// Log::debug("Set root to " + root_);
// }
// else if (directive == "host")
// {
// host_ = value;
// Log::debug("Set host to " + host_);
// }
// else if (directive == "cgi_pass")
// {
// cgi_pass_ = value;
// Log::debug("Set cgi_pass to " + cgi_pass_);
// }
// else if (directive == "cgi_ext")
// {
// cgi_ext_ = value;
// Log::debug("Set cgi_ext to " + cgi_ext_);
// }
// else if (directive == "index")
// {
// index_files_.clear();
// std::string indexFile;
// while (lineStream >> indexFile)
// {
// index_files_.push_back(indexFile);
// Log::debug("Added index file: " + indexFile);
// }
// }
// else if (directive == "error_page")
// {
// int statusCode = std::stoi("-1");
// std::string errorPagePath;
// lineStream >> errorPagePath;
// Log::debug("Set error_page for status " + std::to_string(statusCode) + " to " + errorPagePath);
// }
// else
// {
// Log::warning("Unknown directive: " + directive);
// }
// }
// }
// }
// const LocationConfig &ServerConfig::getLocation(const std::string &path) const
// {
// if (locations_.count(path) > 0) // NOLINT
// {
// return locations_.at(path);
// }
// Log::error("Location not found: " + path);
// throw std::runtime_error("Location not found: " + path);
// }
// std::vector<std::string> ServerConfig::getLocationPaths() const
// {
// std::vector<std::string> paths;
// paths.reserve(locations_.size());
// for (const auto &pair : locations_)
// {
// paths.push_back(pair.first);
// }
// return paths;
// }
void ServerConfig::parseDirectives(const std::string &declarations)
{
Log::info("Parsing server directives");
Log::trace(LOCATION);
std::stringstream ss(declarations);
std::string line;
std::istringstream stream(declarations);
while (std::getline(stream, line))
while (ss.good())
{
std::string directive;
std::istringstream lineStream{line};
lineStream >> directive;
if (!directive.empty())
std::getline(ss, line);
line = utils::trim(line);
if (line.empty())
{
std::string value;
lineStream >> value;
if (directive == "listen")
{
continue;
}
auto directive = DirectiveFactory::createDirective(line);
directives_.push_back(std::move(directive));
}
Log::info("Parsed " + std::to_string(directives_.size()) + " directives.", {{"declarations", declarations}});
}
port_ = std::stoi(value);
if (port_ < 1 || port_ > 65535)
{
throw std::runtime_error("Invalid port number: " + std::to_string(port_));
}
Log::debug("Set port to " + std::to_string(port_));
}
else if (directive == "root")
{
root_ = value;
Log::debug("Set root to " + root_);
}
else if (directive == "host")
{
host_ = value;
Log::debug("Set host to " + host_);
}
else if (directive == "cgi_pass")
{
cgi_pass_ = value;
Log::debug("Set cgi_pass to " + cgi_pass_);
}
else if (directive == "cgi_ext")
{
cgi_ext_ = value;
Log::debug("Set cgi_ext to " + cgi_ext_);
}
else if (directive == "index")
{
index_files_.clear();
std::string indexFile;
while (lineStream >> indexFile)
{
index_files_.push_back(indexFile);
Log::debug("Added index file: " + indexFile);
}
}
else if (directive == "error_page")
{
int statusCode = std::stoi("-1");
std::string errorPagePath;
lineStream >> errorPagePath;
Log::debug("Set error_page for status " + std::to_string(statusCode) + " to " + errorPagePath);
}
else
{
Log::warning("Unknown directive: " + directive);
}
DirectiveValue ServerConfig::operator[](const std::string &directive) const
{
for (const auto& dir : directives_)
{
if (dir->getName() == directive)
{
return dir->get();
}
}
}
const LocationConfig &ServerConfig::getLocation(const std::string &path) const
{
if (locations_.count(path) > 0) // NOLINT
{
return locations_.at(path);
}
Log::error("Location not found: " + path);
throw std::runtime_error("Location not found: " + path);
}
std::vector<std::string> ServerConfig::getLocationPaths() const
{
std::vector<std::string> paths;
paths.reserve(locations_.size());
for (const auto &pair : locations_)
{
paths.push_back(pair.first);
}
return paths;
throw std::runtime_error("Directive not found: " + directive);
}

View File

@ -1,8 +1,10 @@
#pragma once
#include "webserv/config/directive/ADirective.hpp"
#include <webserv/config/LocationConfig.hpp>
#include <map>
#include <memory>
#include <string>
#include <vector>
@ -12,22 +14,24 @@ class ServerConfig
public:
ServerConfig(const std::string &serverBlock);
[[nodiscard]] const std::string &getHost() const { return host_; }
// [[nodiscard]] const std::string &getHost() const { return host_; }
[[nodiscard]] int getPort() const { return port_; }
// [[nodiscard]] int getPort() const { return port_; }
[[nodiscard]] const std::string &getRoot() const { return root_; }
// [[nodiscard]] const std::string &getRoot() const { return root_; }
[[nodiscard]] const std::string &getCgiPass() const { return cgi_pass_; }
// [[nodiscard]] const std::string &getCgiPass() const { return cgi_pass_; }
[[nodiscard]] const std::string &getCgiExt() const { return cgi_ext_; }
// [[nodiscard]] const std::string &getCgiExt() const { return cgi_ext_; }
[[nodiscard]] const std::map<int, std::string> &getErrorPages() const { return error_page_; }
// [[nodiscard]] const std::map<int, std::string> &getErrorPages() const { return error_page_; }
[[nodiscard]] const std::vector<std::string> &getIndexFiles() const { return index_files_; }
// [[nodiscard]] const std::vector<std::string> &getIndexFiles() const { return index_files_; }
[[nodiscard]] const LocationConfig &getLocation(const std::string &path) const;
[[nodiscard]] std::vector<std::string> getLocationPaths() const;
// [[nodiscard]] const LocationConfig &getLocation(const std::string &path) const;
// [[nodiscard]] std::vector<std::string> getLocationPaths() const;
DirectiveValue operator[](const std::string &directive) const;
private:
std::string host_;
@ -38,6 +42,7 @@ class ServerConfig
std::map<int, std::string> error_page_;
std::vector<std::string> index_files_;
std::map<std::string, LocationConfig> locations_;
std::vector<std::unique_ptr<ADirective>> directives_;
void parseServerBlock(const std::string &block);
void parseDirectives(const std::string &declarations);

View File

@ -1,7 +1,6 @@
#pragma once
#include <any>
#include <array>
#include <string>
class DirectiveValue
@ -40,7 +39,7 @@ class ADirective
void setName(const std::string &name);
protected:
std::string name_;
std::string name_; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes)
};
// Supported directives:

View File

@ -87,7 +87,7 @@ void Server::setupServerSocket(const ServerConfig &config)
try
{
std::unique_ptr<Socket> serverSocket = std::make_unique<Socket>();
serverSocket->bind(config.getHost(), config.getPort());
serverSocket->bind(config["host"], config["listen"]);
serverSocket->listen(SOMAXCONN);
int server_fd = serverSocket->getFd();
@ -95,7 +95,7 @@ void Server::setupServerSocket(const ServerConfig &config)
listeners_.push_back(std::move(serverSocket));
fdToConfig_.insert({server_fd, std::cref(config)});
Log::info("Server listening on " + config.getHost() + ":" + std::to_string(config.getPort()) + "...");
// Log::info("Server listening on " + std::string(config["host"]) + ":" + static_cast<std::string>(config["listen"]) + "...");
}
catch (const std::exception &e)
{