diff --git a/webserv/client/Client.cpp b/webserv/client/Client.cpp index 9e69fed..b71633e 100644 --- a/webserv/client/Client.cpp +++ b/webserv/client/Client.cpp @@ -42,17 +42,19 @@ void Client::request() buffer[bytesRead] = '\0'; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) httpRequest_->receiveData(buffer, static_cast(bytesRead)); - if (httpRequest_->getState() == HttpRequest::State::Complete) + if (httpRequest_->getState() == HttpRequest::State::Complete || + httpRequest_->getState() == HttpRequest::State::ParseError) { - Log::info("Received complete request", { - {"request_method", httpRequest_->getMethod()}, - {"request_target", httpRequest_->getTarget()}, - {"http_version", httpRequest_->getHttpVersion()}, - {"headers", httpRequest_->getHeaders().toString()}, - {"body", httpRequest_->getBody()}, - }); + Log::info("Received complete request", + { + {"request_method", httpRequest_->getMethod()}, + {"request_target", httpRequest_->getTarget()}, + {"http_version", httpRequest_->getHttpVersion()}, + {"headers", httpRequest_->getHeaders().toString()}, + {"body", httpRequest_->getBody()}, + {"state", std::to_string(static_cast(httpRequest_->getState()))}, + }); server_.responseReady(client_socket_->getFd()); - httpRequest_->reset(); } else { @@ -66,8 +68,20 @@ void Client::request() std::string Client::getResponse() const { - std::string response = "HTTP/1.1 200 OK\r\nContent-Length: 32\r\n\r\nHello, World!"; - response += " Server port " + std::to_string(server_config_.getPort()) + "\r\n"; + Log::trace(LOCATION); + std::string response = "HTTP/1.1 "; + if (httpRequest_->getState() == HttpRequest::State::ParseError) + { + response += "400 Bad Request\r\n"; + } + else + { + response += "200 OK\r\n"; + } + // 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"; + Log::debug("Sending response:\n" + response); return response; } \ No newline at end of file diff --git a/webserv/config/utils.cpp b/webserv/config/utils.cpp index 98ee024..38ef03c 100644 --- a/webserv/config/utils.cpp +++ b/webserv/config/utils.cpp @@ -1,3 +1,4 @@ + #include #include @@ -7,11 +8,15 @@ namespace utils { size_t stoul(const std::string &str, int base) { + if (str.find_first_not_of("0123456789abcdefABCDEF") != std::string::npos) + { + throw std::invalid_argument("Invalid number: " + str); + } size_t idx = 0; unsigned long value = std::stoul(str, &idx, base); if (idx != str.length()) { - throw std::invalid_argument("Invalid characters in number: " + str); + throw std::invalid_argument("Invalid number with extra characters: " + str); } return value; } diff --git a/webserv/http/HttpHeaders.cpp b/webserv/http/HttpHeaders.cpp index a85e070..28d1c52 100644 --- a/webserv/http/HttpHeaders.cpp +++ b/webserv/http/HttpHeaders.cpp @@ -16,20 +16,7 @@ std::optional HttpHeaders::getContentLength() const { return std::nullopt; } - if (value.find_first_not_of("0123456789") != std::string::npos) - { - Log::warning("Non-numeric Content-Length header value: " + value); - return std::nullopt; - } - try - { - return utils::stoul(value); - } - catch (...) - { - Log::warning("Invalid Content-Length header value: " + value); - return std::nullopt; - } + return utils::stoul(value); } std::optional HttpHeaders::getContentType() const diff --git a/webserv/http/HttpRequest.cpp b/webserv/http/HttpRequest.cpp index 1563f3e..c4eb869 100644 --- a/webserv/http/HttpRequest.cpp +++ b/webserv/http/HttpRequest.cpp @@ -1,3 +1,5 @@ +#include "webserv/config/utils.hpp" + #include // for CRLF, DOUBLE_CRLF #include #include // for Log, LOCATION @@ -47,36 +49,45 @@ void HttpRequest::parseBuffer() { while (true) { - switch (state_) + try { - case State::RequestLine: - if (!parseBufferforRequestLine()) + switch (state_) { - return; // Wait for more data + case State::RequestLine: + if (!parseBufferforRequestLine()) + { + return; // Wait for more data + } + break; + case State::Headers: + if (!parseBufferforHeaders()) + { + return; // Wait for more data + } + break; + case State::Body: + if (!parseBufferforBody()) + { + return; // Wait for more data + } + break; + case State::Chunked: + if (!parseBufferforChunkedBody()) + { + return; // Wait for more data + } + break; + case State::Complete: + Log::debug("HttpRequest::parseBuffer() request is complete"); + return; // Request is complete + case State::ParseError: Log::warning("Parse error occurred, stopping further processing"); return; } - break; - case State::Headers: - if (!parseBufferforHeaders()) - { - return; // Wait for more data - } - break; - case State::Body: - if (!parseBufferforBody()) - { - return; // Wait for more data - } - break; - case State::Chunked: - if (!parseBufferforChunkedBody()) - { - return; // Wait for more data - } - break; - case State::Complete: - Log::debug("HttpRequest::parseBuffer() request is complete"); - return; // Request is complete - case State::ParseError: Log::warning("Parse error occurred, stopping further processing"); return; + } + catch (...) + { + Log::error("Exception during parsing, marking request as ParseError"); + state_ = State::ParseError; + return; } } } @@ -124,10 +135,8 @@ bool HttpRequest::parseBufferforHeaders() Log::debug("Headers waiting for more data: " + LOCATION); return false; // Wait for more data } - // headers_ = buffer_.substr(0, pos + Http::Protocol::CRLF.size()); // Include the last \r\n headers_.parse(buffer_.substr(0, pos + Http::Protocol::CRLF.size())); buffer_.erase(0, pos + Http::Protocol::DOUBLE_CRLF.size()); - // parseContentLength(); if (this->headers_.getContentLength().value_or(0) > 0) { @@ -156,17 +165,9 @@ bool HttpRequest::parseBufferforChunkedBody() return false; } std::string chunkSizeStr = buffer_.substr(0, pos); - size_t chunkSize = 0; - try - { - chunkSize = std::stoul(chunkSizeStr, nullptr, 16); - } - catch (const std::exception &e) - { - Log::warning("Invalid chunk size: " + chunkSizeStr + " (" + e.what() + ")"); - state_ = State::ParseError; // Mark as complete to avoid further processing - return true; - } + Log::debug("Chunk size string: " + chunkSizeStr); + size_t chunkSize = utils::stoul(chunkSizeStr, 16); + Log::warning("Invalid chunk size: " + chunkSizeStr); if (chunkSize == 0) { state_ = State::Complete; // Last chunk