Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
b7758be
refactor(http): add ParseException, processHttp facade and harden isV…
byronlove111 Jun 18, 2026
ff335cc
refactor(parser): single-pass parse, split helpers, harden validation
byronlove111 Jun 18, 2026
e743cee
style(parser): replace ternary with if/else in parseHeaderLine
byronlove111 Jun 18, 2026
2c4b260
fix(parser): respect Content-Length in body parsing, validate it's a …
byronlove111 Jun 19, 2026
ad43ed4
docs(router): add inline comments explaining longest prefix match logic
byronlove111 Jun 19, 2026
c00766d
chore(build): update Makefile to output object files in 'obj/' direct…
byronlove111 Jun 19, 2026
b93ea93
feat(response): add Server: webserv/1.0 header to all responses
byronlove111 Jun 19, 2026
1784db7
docs(response): add inline comments to ResponseBuilder::build
byronlove111 Jun 19, 2026
84b7a5e
refactor(handler): extract buildRedirect helper, remove inline 301 co…
byronlove111 Jun 19, 2026
3eaf710
fix(handler): init bytesRead=0, remove redundant location root guard …
byronlove111 Jun 19, 2026
1a05908
docs(handler): add inline comments to MethodHandler, isCgiRequest and…
byronlove111 Jun 19, 2026
cb0e95d
refactor(http): split HttpUtils into builders/ + utils/
byronlove111 Jun 19, 2026
85bf91a
refactor(handler): extract URI path extraction and file deletion logic
byronlove111 Jun 19, 2026
6cea680
feat(utils): add extractUriPath function for URI processing
byronlove111 Jun 19, 2026
7558ebc
feat(http): implement writeFdFromString utility for writing data to f…
byronlove111 Jun 19, 2026
c471326
refactor(cgi): use extractUriPath in buildEnv for PATH_INFO
byronlove111 Jun 19, 2026
c910a8f
fix(http): correct indentation in processHttp function
byronlove111 Jun 20, 2026
bc0a6a6
fix(parser): normalize header keys to lowercase on storage
byronlove111 Jun 20, 2026
a93cd86
fix(tests): update unit tests for lowercase header key normalization
byronlove111 Jun 20, 2026
9499e1f
fix(tests): align integration tests with lowercase header convention
byronlove111 Jun 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
*.o
obj/

# test binaries (built locally from tests/)
test_parser
Expand Down
7 changes: 4 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,20 @@ CXX = c++
CXXFLAGS = -Wall -Wextra -Werror -std=c++98

SRCS = $(shell find src -name "*.cpp")
OBJS = $(SRCS:.cpp=.o)
OBJS = $(SRCS:src/%.cpp=obj/%.o)
INCS = -I include

all: $(NAME)

$(NAME): $(OBJS)
$(CXX) $(CXXFLAGS) $(OBJS) -o $(NAME)

%.o: %.cpp
obj/%.o: src/%.cpp
@mkdir -p $(dir $@)
$(CXX) $(CXXFLAGS) $(INCS) -c $< -o $@

clean:
rm -f $(OBJS)
rm -rf obj

fclean: clean
rm -f $(NAME)
Expand Down
21 changes: 17 additions & 4 deletions include/http/RequestParser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,29 @@

#include "HttpRequest.hpp"
#include <string>
#include <exception>

class RequestParser {
public:
class ParseException : public std::exception {
public:
ParseException(int code, const std::string& msg) : _code(code), _msg(msg) {}
~ParseException() throw() {}
int getCode() const { return _code; }
const char* what() const throw() { return _msg.c_str(); }
private:
int _code;
std::string _msg;
};

HttpRequest parse(const std::string& raw);

private:
bool isValid(const std::string& raw);
void parseFirstLine(const std::string& line, HttpRequest& req);
void parseHeaders(const std::string& raw, HttpRequest& req, std::size_t firstLineEnd, std::size_t headerBodySep);
void parseBody(const std::string& raw, HttpRequest& req, std::size_t headerBodySep);
void parseRequestLine(const std::string& firstLine, HttpRequest& req);
void parseHeaderLine(const std::string& line, std::string& key, std::string& value);
void validateHostHeader(const std::string& value, bool& hasHostHeader);
void parseHeaders(const std::string& raw, HttpRequest& req, std::size_t firstLineEnd, std::size_t headerBodySep);
void parseBody(const std::string& raw, HttpRequest& req, std::size_t headerBodySep);
};

#endif
13 changes: 13 additions & 0 deletions include/http/builders/HttpBuilders.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#ifndef HTTP_BUILDERS_HPP
#define HTTP_BUILDERS_HPP

#include "../HttpResponse.hpp"
#include <string>

HttpResponse buildHttpError(int statusCode, const std::string& statusMessage);
HttpResponse buildHttpOk(const std::string& body, const std::string& contentType);
HttpResponse buildHttpCreated(const std::string& body);
HttpResponse buildHttpNoContent();
HttpResponse buildRedirect(const std::string& url);

#endif
9 changes: 9 additions & 0 deletions include/http/processHttp.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#ifndef PROCESS_HTTP_HPP
#define PROCESS_HTTP_HPP

#include "../config/ServerConfig.hpp"
#include <string>

std::string processHttp(const std::string& rawRequest, const ServerConfig& server);

#endif
6 changes: 3 additions & 3 deletions include/http/utils/HttpUtils.hpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#ifndef HTTP_UTILS_HPP
#define HTTP_UTILS_HPP

#include "../HttpResponse.hpp"
#include <string>

HttpResponse buildHttpError(int statusCode, const std::string& statusMessage);
std::string getContentType(const std::string& filePath);
bool writeFdFromString(int fd, const std::string& data);
bool readFdToString(int fd, std::string& body);
std::string getContentType(const std::string& filePath);

#endif
1 change: 1 addition & 0 deletions include/http/utils/StringUtils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

std::string urlDecode(const std::string& encoded);
bool hasPathTraversal(const std::string& uri);
std::string extractUriPath(const std::string& uri);
std::string extractQueryString(const std::string& uri);
std::string extractFilename(const std::string& uri);

Expand Down
16 changes: 16 additions & 0 deletions src/http/builders/buildHttpCreated.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include "../../../include/http/builders/HttpBuilders.hpp"
#include <sstream>

HttpResponse buildHttpCreated(const std::string& body)
{
HttpResponse response;
std::ostringstream contentLength;

response.status_code = 201;
response.status_msg = "Created";
response.body = body;
response.headers["Content-Type"] = "text/plain";
contentLength << body.size();
response.headers["Content-Length"] = contentLength.str();
return response;
}
16 changes: 16 additions & 0 deletions src/http/builders/buildHttpError.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include "../../../include/http/builders/HttpBuilders.hpp"
#include <sstream>

HttpResponse buildHttpError(int statusCode, const std::string& statusMessage)
{
HttpResponse response;
std::ostringstream contentLength;

response.status_code = statusCode;
response.status_msg = statusMessage;
response.body = "<html><body><h1>" + statusMessage + "</h1></body></html>";
response.headers["Content-Type"] = "text/html";
contentLength << response.body.size();
response.headers["Content-Length"] = contentLength.str();
return response;
}
10 changes: 10 additions & 0 deletions src/http/builders/buildHttpNoContent.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include "../../../include/http/builders/HttpBuilders.hpp"

HttpResponse buildHttpNoContent()
{
HttpResponse response;
response.status_code = 204;
response.status_msg = "No Content";
response.headers["Content-Length"] = "0";
return response;
}
16 changes: 16 additions & 0 deletions src/http/builders/buildHttpOk.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include "../../../include/http/builders/HttpBuilders.hpp"
#include <sstream>

HttpResponse buildHttpOk(const std::string& body, const std::string& contentType)
{
HttpResponse response;
std::ostringstream contentLength;

response.status_code = 200;
response.status_msg = "OK";
response.body = body;
response.headers["Content-Type"] = contentType;
contentLength << body.size();
response.headers["Content-Length"] = contentLength.str();
return response;
}
11 changes: 11 additions & 0 deletions src/http/builders/buildRedirect.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include "../../../include/http/builders/HttpBuilders.hpp"

HttpResponse buildRedirect(const std::string& url)
{
HttpResponse response;
response.status_code = 301;
response.status_msg = "Moved Permanently";
response.headers["Location"] = url;
response.headers["Content-Length"] = "0";
return response;
}
10 changes: 3 additions & 7 deletions src/http/cgi/env.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,11 @@ std::vector<std::string> CgiHandler::buildEnv(const HttpRequest& request,
envVars.push_back("QUERY_STRING=" + extractQueryString(request.uri));
envVars.push_back("SCRIPT_FILENAME=" + scriptPath);

std::string pathWithoutQuery = request.uri;
std::size_t queryPosition = pathWithoutQuery.find('?');
if (queryPosition != std::string::npos)
pathWithoutQuery = pathWithoutQuery.substr(0, queryPosition);
envVars.push_back("PATH_INFO=" + pathWithoutQuery);
envVars.push_back("PATH_INFO=" + extractUriPath(request.uri));

std::map<std::string, std::string>::const_iterator headerIt;

headerIt = request.headers.find("Content-Type");
headerIt = request.headers.find("content-type");
if (headerIt != request.headers.end())
envVars.push_back("CONTENT_TYPE=" + headerIt->second);
else
Expand All @@ -34,7 +30,7 @@ std::vector<std::string> CgiHandler::buildEnv(const HttpRequest& request,
else
envVars.push_back("CONTENT_LENGTH=0");

headerIt = request.headers.find("Host");
headerIt = request.headers.find("host");
if (headerIt != request.headers.end())
envVars.push_back("HTTP_HOST=" + headerIt->second);

Expand Down
Loading
Loading