feat : add structural validation rules to ConfigValidator

This commit is contained in:
whaffman 2025-10-06 16:00:38 +02:00
parent 4f89a2918c
commit dbc318cdfa
6 changed files with 69 additions and 58 deletions

View File

@ -1,5 +1,4 @@
#include <webserv/config/validation/ConfigValidator.hpp>
#include <webserv/config/validation/ValidationEngine.hpp> // for ValidationEngine
#include <webserv/config/validation/directive_rules/AValidationRule.hpp> // for AValidationRule
#include <webserv/config/validation/directive_rules/AllowedValuesRule.hpp> // for AllowedValuesRule

View File

@ -1,9 +1,8 @@
#include <webserv/config/validation/ValidationEngine.hpp>
#include <webserv/config/AConfig.hpp> // for AConfig
#include <webserv/config/GlobalConfig.hpp> // for GlobalConfig
#include <webserv/config/LocationConfig.hpp> // for LocationConfig
#include <webserv/config/ServerConfig.hpp> // for ServerConfig
#include <webserv/config/validation/ValidationEngine.hpp>
#include <webserv/config/validation/ValidationResult.hpp> // for ValidationResult
#include <webserv/config/validation/directive_rules/AValidationRule.hpp> // for AValidationRule
#include <webserv/log/Log.hpp> // for Log, LOCATION
@ -31,7 +30,8 @@ void ValidationEngine::addLocationRule(const std::string &directiveName, std::un
void ValidationEngine::addStructuralRule(std::unique_ptr<AStructuralValidationRule> rule)
{
Log::trace(LOCATION);
if (rule != nullptr) {
if (rule != nullptr)
{
structuralRules_.push_back(std::move(rule));
}
}
@ -76,7 +76,7 @@ std::vector<ValidationResult> ValidationEngine::getWarnings() const
bool ValidationEngine::hasErrors() const
{
for (const auto &result : results_) //NOLINT(readability-use-anyofallof)
for (const auto &result : results_) // NOLINT(readability-use-anyofallof)
{
if (!result.isValidResult())
{
@ -122,20 +122,25 @@ void ValidationEngine::validateConfig(RuleMap const &rulesMap, const AConfig *co
void ValidationEngine::validateLocationConfig(const std::string &path, const LocationConfig *config)
{
Log::trace(LOCATION);
// Run location structural validation rules
for (const auto &rule : structuralRules_) {
try {
for (const auto &rule : structuralRules_)
{
try
{
ValidationResult result = rule->validateLocation(config);
if (!result.isValidResult()) {
if (!result.isValidResult())
{
results_.push_back(result);
}
} catch (const std::exception &e) {
results_.push_back(ValidationResult::error(
"Structural rule '" + rule->getRuleName() + "' threw exception for location '" + path + "': " + e.what()));
}
catch (const std::exception &e)
{
results_.push_back(ValidationResult::error("Structural rule '" + rule->getRuleName() +
"' threw exception for location '" + path + "': " + e.what()));
}
}
// Run location directive validation rules
validateConfig(locationRules_, config);
}
@ -143,23 +148,28 @@ void ValidationEngine::validateLocationConfig(const std::string &path, const Loc
void ValidationEngine::validateServerConfig(const ServerConfig *config)
{
Log::trace(LOCATION);
// Run server structural validation rules
for (const auto &rule : structuralRules_) {
try {
for (const auto &rule : structuralRules_)
{
try
{
ValidationResult result = rule->validateServer(config);
if (!result.isValidResult()) {
if (!result.isValidResult())
{
results_.push_back(result);
}
} catch (const std::exception &e) {
results_.push_back(ValidationResult::error(
"Structural rule '" + rule->getRuleName() + "' threw exception: " + e.what()));
}
catch (const std::exception &e)
{
results_.push_back(
ValidationResult::error("Structural rule '" + rule->getRuleName() + "' threw exception: " + e.what()));
}
}
// Run server directive validation rules
validateConfig(serverRules_, config);
for (const auto &path : config->getLocationPaths())
{
const LocationConfig *locationConfig = config->getLocation(path);
@ -173,23 +183,28 @@ void ValidationEngine::validateServerConfig(const ServerConfig *config)
void ValidationEngine::validateGlobalConfig(const GlobalConfig *config)
{
Log::trace(LOCATION);
// Run global structural validation rules
for (const auto &rule : structuralRules_) {
try {
for (const auto &rule : structuralRules_)
{
try
{
ValidationResult result = rule->validateGlobal(config);
if (!result.isValidResult()) {
if (!result.isValidResult())
{
results_.push_back(result);
}
} catch (const std::exception &e) {
results_.push_back(ValidationResult::error(
"Structural rule '" + rule->getRuleName() + "' threw exception: " + e.what()));
}
catch (const std::exception &e)
{
results_.push_back(
ValidationResult::error("Structural rule '" + rule->getRuleName() + "' threw exception: " + e.what()));
}
}
// Run global directive validation rules
validateConfig(globalRules_, config);
for (const auto *serverConfig : config->getServerConfigs())
{
validateServerConfig(serverConfig);
@ -205,7 +220,7 @@ void ValidationEngine::validate()
{
Log::trace(LOCATION);
results_.clear(); // Clear previous results
if (globalConfig_ != nullptr)
{
validateGlobalConfig(globalConfig_);

View File

@ -4,8 +4,8 @@
#include <webserv/config/GlobalConfig.hpp>
#include <webserv/config/LocationConfig.hpp>
#include <webserv/config/ServerConfig.hpp>
#include <webserv/config/validation/ValidationResult.hpp> // for ValidationResult
#include <webserv/config/validation/directive_rules/AValidationRule.hpp> // for AValidationRule
#include <webserv/config/validation/ValidationResult.hpp> // for ValidationResult
#include <webserv/config/validation/directive_rules/AValidationRule.hpp> // for AValidationRule
#include <webserv/config/validation/structural_rules/AStructuralValidationRule.hpp> // for AStructuralValidationRule
#include <map> // for map

View File

@ -10,15 +10,17 @@ class LocationConfig;
class AStructuralValidationRule
{
private:
private:
std::string ruleName_;
std::string description_;
protected:
protected:
AStructuralValidationRule(const std::string &ruleName, const std::string &description)
: ruleName_(ruleName), description_(description) {}
: ruleName_(ruleName), description_(description)
{
}
public:
public:
virtual ~AStructuralValidationRule() = default;
AStructuralValidationRule(const AStructuralValidationRule &other) = delete;
@ -29,30 +31,24 @@ public:
// Virtual validation methods - override as needed
[[nodiscard]] virtual ValidationResult validateGlobal(const GlobalConfig *config) const
{
static_cast<void>(config); // Suppress unused parameter warning
static_cast<void>(config); // Suppress unused parameter warning
return ValidationResult::success(); // Default: no global validation
}
[[nodiscard]] virtual ValidationResult validateServer(const ServerConfig *config) const
{
static_cast<void>(config); // Suppress unused parameter warning
static_cast<void>(config); // Suppress unused parameter warning
return ValidationResult::success(); // Default: no server validation
}
[[nodiscard]] virtual ValidationResult validateLocation(const LocationConfig *config) const
{
static_cast<void>(config); // Suppress unused parameter warning
static_cast<void>(config); // Suppress unused parameter warning
return ValidationResult::success(); // Default: no location validation
}
// Non-virtual getters - set in constructor
[[nodiscard]] std::string getRuleName() const
{
return ruleName_;
}
[[nodiscard]] std::string getRuleName() const { return ruleName_; }
[[nodiscard]] std::string getDescription() const
{
return description_;
}
[[nodiscard]] std::string getDescription() const { return description_; }
};

View File

@ -6,8 +6,8 @@
#include <string>
MinimumServerBlocksRule::MinimumServerBlocksRule(size_t minimumServers)
: AStructuralValidationRule("MinimumServerBlocksRule",
"Ensures global config has at least " + std::to_string(minimumServers) + " server block(s)"),
: AStructuralValidationRule("MinimumServerBlocksRule", "Ensures global config has at least " +
std::to_string(minimumServers) + " server block(s)"),
minimumServers_(minimumServers)
{
}
@ -16,16 +16,17 @@ ValidationResult MinimumServerBlocksRule::validateGlobal(const GlobalConfig *con
{
Log::trace(LOCATION);
if (config == nullptr) {
if (config == nullptr)
{
return ValidationResult::error("Global config is null");
}
size_t serverCount = config->getServerConfigs().size();
if (serverCount < minimumServers_) {
return ValidationResult::error(
"Global configuration must have at least " + std::to_string(minimumServers_) +
" server block(s), but found " + std::to_string(serverCount));
if (serverCount < minimumServers_)
{
return ValidationResult::error("Global configuration must have at least " + std::to_string(minimumServers_) +
" server block(s), but found " + std::to_string(serverCount));
}
return ValidationResult::success();

View File

@ -8,10 +8,10 @@ class GlobalConfig;
class MinimumServerBlocksRule : public AStructuralValidationRule
{
private:
private:
size_t minimumServers_;
public:
public:
explicit MinimumServerBlocksRule(size_t minimumServers = 1);
~MinimumServerBlocksRule() override = default;