fix: add error handling for null bytes in config files and enforce location path rules

This commit is contained in:
whaffman 2025-10-31 15:10:00 +01:00
parent fe3b28fbfe
commit e792429b50
9 changed files with 61 additions and 5 deletions

View File

@ -55,8 +55,12 @@ void ConfigManager::parseConfigFile(const std::string &filePath)
{
throw std::runtime_error("Config file is empty: " + filePath);
}
utils::removeComments(content);
if (content.find('\0') != std::string::npos)
{
throw std::runtime_error("null byte detected in config file: " + filePath);
}
globalConfig_ = std::make_unique<GlobalConfig>(content);
// Implement this function to handle global config

View File

@ -50,7 +50,7 @@ void GlobalConfig::parseBlock(const std::string &block)
pos = closeBrace + 1;
}
if (block.find("location", 0) != std::string::npos)
if (directives.find("location", 0) != std::string::npos)
{
throw std::runtime_error("Location blocks are not allowed in the global context.");
}

View File

@ -48,6 +48,12 @@ void ServerConfig::parseBlock(const std::string &block)
std::string locationPath
= utils::trim(block.substr(locationPos + 9, bracePos - (locationPos + 9))); // TODO magic numbers
// Add global declarations before this server block
if (locationPath.front() != '/')
{
throw std::runtime_error("Location path must start with '/': " + locationPath);
}
directives += block.substr(pos, locationPos - pos);
size_t closeBrace = utils::findCorrespondingClosingBrace(block, bracePos);
if (closeBrace == std::string::npos)

View File

@ -37,6 +37,8 @@ std::unique_ptr<ADirective> DirectiveFactory::createDirective(const std::string
{
throw std::invalid_argument("Directive argument is empty: " + name);
}
if (type.empty())
{
throw std::invalid_argument("Unsupported directive: " + name);

View File

@ -1,7 +1,7 @@
#include <webserv/config/directive/IntDirective.hpp> // for IntDirective
#include <webserv/config/directive/ADirective.hpp> // for ADirective
#include <webserv/config/directive/DirectiveValue.hpp> // for DirectiveValueType
#include <webserv/config/directive/IntDirective.hpp> // for IntDirective
#include <webserv/log/Log.hpp> // for Log
IntDirective::IntDirective(const std::string &name, const std::string &value)
: ADirective(name) // NOLINT(bugprone-easily-swappable-parameters)
@ -11,7 +11,19 @@ IntDirective::IntDirective(const std::string &name, const std::string &value)
void IntDirective::parse(const std::string &value)
{
value_ = std::stoi(value); // TODO: check parsing
try
{
value_ = std::stoi(value);
Log::debug("IntDirective: parsed integer value " + std::to_string(value_) + " from string \"" + value + "\"");
}
catch (const std::invalid_argument &e)
{
throw std::invalid_argument("numeric value expected");
}
catch (const std::out_of_range &e)
{
throw std::invalid_argument("IntDirective: integer out of range");
}
}
DirectiveValueType IntDirective::getValueType() const

View File

@ -57,6 +57,11 @@ void SizeDirective::parse(const std::string &value)
}
value_ *= multiplier;
if (value_ > 1000000000UL) // 1 GB limit for sanity should be a constant
{
throw std::invalid_argument("Size directive too large: " + value + " in " + name_);
}
}
DirectiveValueType SizeDirective::getValueType() const

View File

@ -11,6 +11,10 @@ StringDirective::StringDirective(const std::string &name, const std::string &val
void StringDirective::parse(const std::string &value)
{
if (value.size() > 4096) //TODO: use PATH_MAX or NAME_MAX where appropriate
{
throw std::invalid_argument("StringDirective: string value exceeds maximum length");
}
value_ = value;
}

View File

@ -20,6 +20,10 @@ void VectorDirective::parse(const std::string &value)
std::getline(ss, item, ' '); // index indx.html
if (!item.empty())
{
if (item.size() > 4096) //TODO: use PATH_MAX or NAME_MAX where appropriate
{
throw std::invalid_argument("VectorDirective: string value exceeds maximum length");
}
value_.push_back(item);
}
}

View File

@ -47,6 +47,18 @@ void HttpRequest::setState(State state)
state_ = State::ParseError;
return;
}
if (target_.starts_with("http://") || target_.starts_with("https://"))
{
size_t pos = target_.find('/', 8); // Skip "http://" or "https://"
if (pos == std::string::npos)
{
target_ = "/";
}
else
{
target_ = target_.substr(pos);
}
}
uri_ = std::make_unique<URI>(*this, *serverConfig);
}
state_ = state;
@ -176,6 +188,13 @@ bool HttpRequest::parseBufferforHeaders()
state_ = State::Body;
return true;
}
if (headers_.has("X-Folded-Header"))
{
Log::debug("HttpRequest::parseBuffer() in state Headers with folded headers");
client_->getHttpResponse().setError(400);
setState(State::ParseError);
return false;
}
if (this->headers_.has("Transfer-Encoding") && this->headers_.get("Transfer-Encoding") == "chunked")
{
Log::debug("HttpRequest::parseBuffer() in state Headers with chunked encoding");