fix: add error handling for null bytes in config files and enforce location path rules
This commit is contained in:
parent
fe3b28fbfe
commit
e792429b50
@ -57,6 +57,10 @@ void ConfigManager::parseConfigFile(const std::string &filePath)
|
|||||||
}
|
}
|
||||||
|
|
||||||
utils::removeComments(content);
|
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);
|
globalConfig_ = std::make_unique<GlobalConfig>(content);
|
||||||
|
|
||||||
// Implement this function to handle global config
|
// Implement this function to handle global config
|
||||||
|
|||||||
@ -50,7 +50,7 @@ void GlobalConfig::parseBlock(const std::string &block)
|
|||||||
pos = closeBrace + 1;
|
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.");
|
throw std::runtime_error("Location blocks are not allowed in the global context.");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -48,6 +48,12 @@ void ServerConfig::parseBlock(const std::string &block)
|
|||||||
std::string locationPath
|
std::string locationPath
|
||||||
= utils::trim(block.substr(locationPos + 9, bracePos - (locationPos + 9))); // TODO magic numbers
|
= utils::trim(block.substr(locationPos + 9, bracePos - (locationPos + 9))); // TODO magic numbers
|
||||||
// Add global declarations before this server block
|
// 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);
|
directives += block.substr(pos, locationPos - pos);
|
||||||
size_t closeBrace = utils::findCorrespondingClosingBrace(block, bracePos);
|
size_t closeBrace = utils::findCorrespondingClosingBrace(block, bracePos);
|
||||||
if (closeBrace == std::string::npos)
|
if (closeBrace == std::string::npos)
|
||||||
|
|||||||
@ -37,6 +37,8 @@ std::unique_ptr<ADirective> DirectiveFactory::createDirective(const std::string
|
|||||||
{
|
{
|
||||||
throw std::invalid_argument("Directive argument is empty: " + name);
|
throw std::invalid_argument("Directive argument is empty: " + name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (type.empty())
|
if (type.empty())
|
||||||
{
|
{
|
||||||
throw std::invalid_argument("Unsupported directive: " + name);
|
throw std::invalid_argument("Unsupported directive: " + name);
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
#include <webserv/config/directive/IntDirective.hpp> // for IntDirective
|
|
||||||
|
|
||||||
#include <webserv/config/directive/ADirective.hpp> // for ADirective
|
#include <webserv/config/directive/ADirective.hpp> // for ADirective
|
||||||
#include <webserv/config/directive/DirectiveValue.hpp> // for DirectiveValueType
|
#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)
|
IntDirective::IntDirective(const std::string &name, const std::string &value)
|
||||||
: ADirective(name) // NOLINT(bugprone-easily-swappable-parameters)
|
: 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)
|
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
|
DirectiveValueType IntDirective::getValueType() const
|
||||||
|
|||||||
@ -57,6 +57,11 @@ void SizeDirective::parse(const std::string &value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
value_ *= multiplier;
|
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
|
DirectiveValueType SizeDirective::getValueType() const
|
||||||
|
|||||||
@ -11,6 +11,10 @@ StringDirective::StringDirective(const std::string &name, const std::string &val
|
|||||||
|
|
||||||
void StringDirective::parse(const std::string &value)
|
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;
|
value_ = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -20,6 +20,10 @@ void VectorDirective::parse(const std::string &value)
|
|||||||
std::getline(ss, item, ' '); // index indx.html
|
std::getline(ss, item, ' '); // index indx.html
|
||||||
if (!item.empty())
|
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);
|
value_.push_back(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,6 +47,18 @@ void HttpRequest::setState(State state)
|
|||||||
state_ = State::ParseError;
|
state_ = State::ParseError;
|
||||||
return;
|
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);
|
uri_ = std::make_unique<URI>(*this, *serverConfig);
|
||||||
}
|
}
|
||||||
state_ = state;
|
state_ = state;
|
||||||
@ -176,6 +188,13 @@ bool HttpRequest::parseBufferforHeaders()
|
|||||||
state_ = State::Body;
|
state_ = State::Body;
|
||||||
return true;
|
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")
|
if (this->headers_.has("Transfer-Encoding") && this->headers_.get("Transfer-Encoding") == "chunked")
|
||||||
{
|
{
|
||||||
Log::debug("HttpRequest::parseBuffer() in state Headers with chunked encoding");
|
Log::debug("HttpRequest::parseBuffer() in state Headers with chunked encoding");
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user