diff --git a/webserv/client/Client.cpp b/webserv/client/Client.cpp index 5a9f899..fe8144e 100644 --- a/webserv/client/Client.cpp +++ b/webserv/client/Client.cpp @@ -81,8 +81,7 @@ void Client::request() buffer[bytesRead] = '\0'; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) httpRequest_->receiveData(static_cast(buffer), static_cast(bytesRead)); - if (httpRequest_->getState() == HttpRequest::State::Complete - || httpRequest_->getState() == HttpRequest::State::ParseError) + if (httpRequest_->getState() == HttpRequest::State::Complete) { Log::info("Received request: " + httpRequest_->getHttpVersion() + " " + httpRequest_->getMethod() + " " + httpRequest_->getTarget() + " "); @@ -92,7 +91,7 @@ void Client::request() {"request_target", httpRequest_->getTarget()}, {"http_version", httpRequest_->getHttpVersion()}, {"headers", httpRequest_->getHeaders().toString()}, - // {"body", httpRequest_->getBody()}, + // {"body", httpRequest_->getBody()}, {"state", std::to_string(static_cast(httpRequest_->getState()))}, }); diff --git a/webserv/http/HttpRequest.cpp b/webserv/http/HttpRequest.cpp index fd96cce..30ef03d 100644 --- a/webserv/http/HttpRequest.cpp +++ b/webserv/http/HttpRequest.cpp @@ -34,10 +34,16 @@ void HttpRequest::setState(State state) { if (state == State::Complete) { + if (! headers_.getHost().has_value()) + { + client_->getHttpResponse().setError(Http::StatusCode::BAD_REQUEST); + state_ = State::ParseError; + return; + } ServerConfig *serverConfig = getServerConfig(); if (serverConfig == nullptr) { - Log::error("No matching server config found for host"); + client_->getHttpResponse().setError(Http::StatusCode::NOT_FOUND); state_ = State::ParseError; return; } @@ -135,6 +141,7 @@ bool HttpRequest::parseBufferforRequestLine() if (parts.size() != 3) { Log::warning("Invalid request line: " + requestLine_); + client_->getHttpResponse().setError(Http::StatusCode::BAD_REQUEST); state_ = State::ParseError; // Mark as complete to avoid further processing return true; } @@ -194,6 +201,7 @@ bool HttpRequest::parseBufferforChunkedBody() catch (const std::exception &e) { Log::warning("Invalid chunk size: " + chunkSizeStr + " - " + e.what()); + client_->getHttpResponse().setError(400); setState(State::ParseError); return false; } diff --git a/webserv/http/HttpRequest.hpp b/webserv/http/HttpRequest.hpp index 94d81ff..7c61afd 100644 --- a/webserv/http/HttpRequest.hpp +++ b/webserv/http/HttpRequest.hpp @@ -1,5 +1,6 @@ #pragma once +#include "webserv/http/HttpResponse.hpp" #include #include // for HttpHeaders diff --git a/webserv/http/HttpResponse.cpp b/webserv/http/HttpResponse.cpp index 2265aa8..617b27a 100644 --- a/webserv/http/HttpResponse.cpp +++ b/webserv/http/HttpResponse.cpp @@ -13,16 +13,31 @@ void HttpResponse::addHeader(const std::string &key, const std::string &value) void HttpResponse::appendBody(const std::vector &data) { + if (complete_) + { + Log::warning("Attempt to set body on a completed HttpResponse"); + return; + } body_.insert(body_.end(), data.begin(), data.end()); } void HttpResponse::appendBody(const std::string &body) { + if (complete_) + { + Log::warning("Attempt to set body on a completed HttpResponse"); + return; + } body_.insert(body_.end(), body.begin(), body.end()); } void HttpResponse::setBody(const std::vector &data) // TODO: validate headers { + if (complete_) + { + Log::warning("Attempt to set body on a completed HttpResponse"); + return; + } body_ = data; setComplete(); } @@ -43,6 +58,12 @@ void HttpResponse::setComplete() complete_ = true; } +void HttpResponse::setError(uint16_t statusCode) +{ + statusCode_ = statusCode; + complete_ = true; +} + bool HttpResponse::isComplete() const noexcept { return complete_; diff --git a/webserv/http/HttpResponse.hpp b/webserv/http/HttpResponse.hpp index 09bb17c..ebcabca 100644 --- a/webserv/http/HttpResponse.hpp +++ b/webserv/http/HttpResponse.hpp @@ -31,6 +31,7 @@ class HttpResponse void setBody(const std::string &body); void setComplete(); + void setError(uint16_t statusCode); void setStatus(uint16_t statusCode); diff --git a/webserv/http/RequestValidator.cpp b/webserv/http/RequestValidator.cpp index 387aeaa..f033295 100644 --- a/webserv/http/RequestValidator.cpp +++ b/webserv/http/RequestValidator.cpp @@ -1,8 +1,9 @@ +#include "webserv/log/Log.hpp" +#include #include -#include - #include +#include #include #include @@ -20,9 +21,43 @@ std::optional RequestValidator::validate() co { return error; } + if (auto error = validateHttpVersion()) + { + return error; + } + if (auto error = validateHostHeader()) + { + return error; + } return std::nullopt; // No validation errors } +std::optional RequestValidator::validateHostHeader() const +{ + if (!request->getHeaders().has("Host")) + { + return ValidationError{400, "Bad Request: Missing Host header"}; + } + std::string hostHeader = request->getHeaders().get("Host"); + // Basic validation: check if host header is not empty + if (hostHeader.empty()) + { + return ValidationError{400, "Bad Request: Empty Host header"}; + } + Log::debug("Host header validated: " + hostHeader); + return std::nullopt; +} + +std::optional RequestValidator::validateHttpVersion() const +{ + std::string httpVersion = request->getHttpVersion(); + if (httpVersion != "HTTP/1.1" && httpVersion != "HTTP/1.0") + { + return ValidationError{505, "HTTP Version Not Supported"}; + } + return std::nullopt; +} + std::optional RequestValidator::validateContentLength() const { size_t bodySize = request->getBody().size(); @@ -48,6 +83,10 @@ std::optional RequestValidator::validateMetho auto allowedMethodsOpt = config->get>("allowed_methods"); std::vector allowedMethods; + if (request->getMethod().empty()) + { + return ValidationError{400, "Bad Request: Empty HTTP Method"}; + } if (allowedMethodsOpt.has_value()) { allowedMethods = std::move(*allowedMethodsOpt); diff --git a/webserv/http/RequestValidator.hpp b/webserv/http/RequestValidator.hpp index 051d115..1b1aa2b 100644 --- a/webserv/http/RequestValidator.hpp +++ b/webserv/http/RequestValidator.hpp @@ -39,4 +39,6 @@ class RequestValidator [[nodiscard]] std::optional validateContentLength() const; [[nodiscard]] std::optional validateMethod() const; + [[nodiscard]] std::optional validateHttpVersion() const; + [[nodiscard]] std::optional validateHostHeader() const; }; \ No newline at end of file diff --git a/webserv/router/Router.cpp b/webserv/router/Router.cpp index dc16dea..cf5854b 100644 --- a/webserv/router/Router.cpp +++ b/webserv/router/Router.cpp @@ -45,13 +45,8 @@ std::unique_ptr Router::handleRequest() Log::trace(LOCATION); HttpRequest &request = client_->getHttpRequest(); - if (request.getState() == HttpRequest::State::ParseError) - { - Log::error("Router::handleRequest() called with incomplete request"); - - return nullptr; - } HttpResponse &response = client_->getHttpResponse(); + const AConfig *config = request.getUri().getConfig(); auto validator = std::make_unique(config, &request);