From f7af2c385018a08d4d3f495494f28ed660061eb1 Mon Sep 17 00:00:00 2001 From: "Gu://em_" Date: Sat, 10 Jan 2026 18:39:50 +0100 Subject: [PATCH 1/3] jv me buter --- httpd/src/daemon/daemon.c | 2 +- httpd/src/daemon/daemon.h | 2 +- httpd/src/http/headers.c | 15 +++-- httpd/src/http/http.c | 64 ++++++++++++++++--- httpd/src/logger/errors.c | 4 +- httpd/src/logger/errors.h | 4 +- .../test_root_dir/test_host_compliance.sh | 40 ++++++++++++ httpd/tests/test_suite.py | 46 +++++++++++++ 8 files changed, 158 insertions(+), 19 deletions(-) create mode 100755 httpd/tests/test_root_dir/test_host_compliance.sh diff --git a/httpd/src/daemon/daemon.c b/httpd/src/daemon/daemon.c index 0e1008c..a918966 100644 --- a/httpd/src/daemon/daemon.c +++ b/httpd/src/daemon/daemon.c @@ -17,7 +17,7 @@ void daemon_init(struct config *cfg) config = cfg; } -int get_pid() +int get_pid(void) { FILE *stream = fopen(config->pid_file, "r"); if (stream == NULL) diff --git a/httpd/src/daemon/daemon.h b/httpd/src/daemon/daemon.h index 5b150ec..f1dcae8 100644 --- a/httpd/src/daemon/daemon.h +++ b/httpd/src/daemon/daemon.h @@ -7,7 +7,7 @@ * * @return */ -int get_pid(); +int get_pid(void); /* @brief */ diff --git a/httpd/src/http/headers.c b/httpd/src/http/headers.c index bf6ba65..88b64bf 100644 --- a/httpd/src/http/headers.c +++ b/httpd/src/http/headers.c @@ -53,7 +53,7 @@ ssize_t parse_headers(struct http_request *res, struct string *req, // Yes I know I do one useless allocation but I really don't care at this // point - while (req->data[i] != '\n') // ! Blank line + while (req->data[i] != '\n' && req->data[i] != '\r') // ! Blank line { if (header == NULL) { @@ -73,21 +73,26 @@ ssize_t parse_headers(struct http_request *res, struct string *req, return ERR_HTTP_OUT_OF_MEMORY; // Read field - ssize_t nread = read_field(req, offset, &header->field); + ssize_t nread = read_field(req, i, &header->field); if (nread <= 0) return nread; // Contains error code when negative - i += nread; + i += nread + 1; // Read value - nread = read_value(req, offset, &header->value); + nread = read_value(req, i, &header->value); if (nread <= 0) return nread; // Contains error code when negative i += nread + 1; } - return i + 1; + if (req->data[i] == '\r') + i++; + if (req->data[i] == '\n') + i++; + + return i; } struct http_header *get_header(struct http_header *headers, const char *field) diff --git a/httpd/src/http/http.c b/httpd/src/http/http.c index c53c468..a7c7198 100644 --- a/httpd/src/http/http.c +++ b/httpd/src/http/http.c @@ -184,10 +184,34 @@ static void check_req(struct http_request *req, struct http_response *resp) != 0) resp->status_code = 400; else if (string_compare_strictly_n_str(req->protocol, "HTTP/1.1", - strlen("HTTP/1.1") != 0)) + strlen("HTTP/1.1")) != 0) resp->status_code = 505; - printf("%s %d\n", req->protocol->data, resp->status_code); + // Host + if (resp->status_code != 400 && resp->status_code != 505) + { + int host_count = 0; + struct http_header *cur = req->headers; + while (cur != NULL) + { + if (cur->field->size == 4 + && string_compare_n_str(cur->field, "Host", 4) == 0) + { + host_count++; + if (cur->value == NULL || cur->value->size == 0) + { + resp->status_code = 400; + break; + } + } + cur = cur->next; + } + + if (host_count != 1) + resp->status_code = 400; + } + + // printf("%s %d\n", req->protocol->data, resp->status_code); } // === Functions @@ -215,7 +239,8 @@ void handle_request(int client_fd, char *client_ip) { string_concat_str(str, buffer, nread); } - string_concat_str(str, buffer, nread); + if (nread > 0) + string_concat_str(str, buffer, nread); // Parse request struct http_request *req = parse_request(str); @@ -288,7 +313,19 @@ struct http_request *parse_request(struct string *req) size_t i = 0; ssize_t nread = parse_reqline(res, req); if (nread <= 0) - return NULL; + { + if (nread == ERR_HTTP_NOT_IMPLEMENTED) + res->status_code = 501; + else + res->status_code = 400; + + if (res->target == NULL) + res->target = string_create("", 0); + if (res->protocol == NULL) + res->protocol = string_create("HTTP/1.1", 8); + + return res; + } // Split path and query split_target(res); @@ -298,7 +335,10 @@ struct http_request *parse_request(struct string *req) // Headers nread = parse_headers(res, req, i); if (nread <= 0) - return NULL; + { + res->status_code = 400; + return res; + } return res; } @@ -317,8 +357,11 @@ struct http_response *generate_response(struct http_request *req) res->protocol = string_create(protocol, strlen(protocol)); // Target - str_concat_string(config->servers->root_dir, - strlen(config->servers->root_dir), req->target); + if (req->status_code == 0) + { + str_concat_string(config->servers->root_dir, + strlen(config->servers->root_dir), req->target); + } // Status code if (req->status_code == 0) @@ -340,7 +383,8 @@ struct http_response *generate_response(struct http_request *req) res->status_code = req->status_code; // Check protocol and method - check_req(req, res); + if (req->status_code == 0) + check_req(req, res); // Headers char *time = get_time(); @@ -362,6 +406,10 @@ struct http_response *generate_response(struct http_request *req) res->status_code = 403; } } + else + { + append_header(&res->headers, create_header("Content-Length", "0")); + } append_header(&res->headers, create_header("Connection", "close")); // Status msg diff --git a/httpd/src/logger/errors.c b/httpd/src/logger/errors.c index 3f96b65..4bbb369 100644 --- a/httpd/src/logger/errors.c +++ b/httpd/src/logger/errors.c @@ -26,7 +26,7 @@ void errlog_init(bool enabled, int logfile_fd, struct server_config *serv_cfg) config.server_cfg = serv_cfg; } -void print_err() +void print_err(void) { print_log_err("%s", get_err()); } @@ -55,7 +55,7 @@ void print_log_err(char *format, ...) fprintf(stderr, "Error: %s", get_err()); } -char *get_err() +char *get_err(void) { return strerror(errno); } diff --git a/httpd/src/logger/errors.h b/httpd/src/logger/errors.h index 931a883..09b8be2 100644 --- a/httpd/src/logger/errors.h +++ b/httpd/src/logger/errors.h @@ -14,7 +14,7 @@ void errlog_init(bool enabled, int logfile_fd, struct server_config *serv_cfg); /* @brief Retrieves the last error with errno and prints the corresponding * error message in the logs and stderr */ -void print_err(); +void print_err(void); /* @brief Prints error logs, just like print_log() but for errors */ @@ -22,6 +22,6 @@ void print_log_err(char *format, ...); /* @brief Returns the string corresponding to the last error that happened */ -char *get_err(); +char *get_err(void); #endif // ! ERRORS_H diff --git a/httpd/tests/test_root_dir/test_host_compliance.sh b/httpd/tests/test_root_dir/test_host_compliance.sh new file mode 100755 index 0000000..6851190 --- /dev/null +++ b/httpd/tests/test_root_dir/test_host_compliance.sh @@ -0,0 +1,40 @@ +#!/bin/sh + +# Simple test script for HTTP/1.1 Host header compliance +# Usage: ./test_host_compliance.sh [IP] [PORT] + +IP=${1:-"127.0.0.1"} +PORT=${2:-"6996"} + +echo "Targeting server at $IP:$PORT" + +test_req() { + NAME="$1" + PAYLOAD="$2" + EXPECTED="$3" + + echo -n "Test: $NAME ... " + # Send payload, wait max 1s for response + RESP=$(printf "$PAYLOAD" | nc -w 1 $IP $PORT 2>/dev/null | head -n 1) + + if echo "$RESP" | grep -q "$EXPECTED"; then + echo "PASS" + else + echo "FAIL (Expected '$EXPECTED', got '$RESP')" + fi +} + +# 1. Valid Request +test_req "Valid Request" "GET / HTTP/1.1\r\nHost: localhost\r\n\r\n" "200 OK" + +# 2. Missing Host Header +test_req "Missing Host" "GET / HTTP/1.1\r\n\r\n" "400 Bad Request" + +# 3. Empty Host Header +test_req "Empty Host" "GET / HTTP/1.1\r\nHost:\r\n\r\n" "400 Bad Request" + +# 4. Multiple Host Headers +test_req "Multiple Hosts" "GET / HTTP/1.1\r\nHost: a\r\nHost: b\r\n\r\n" "400 Bad Request" + +# 5. Bad Protocol Version (Should be 505 now with the fix) +test_req "Bad Protocol (HTTP/1.0)" "GET / HTTP/1.0\r\nHost: localhost\r\n\r\n" "505" \ No newline at end of file diff --git a/httpd/tests/test_suite.py b/httpd/tests/test_suite.py index 37388e2..41352dd 100644 --- a/httpd/tests/test_suite.py +++ b/httpd/tests/test_suite.py @@ -130,3 +130,49 @@ def test_bad_request(): assert response.status == 400 finally: kill_httpd(proc) + +@pytest.mark.timeout(2) +def test_head_index(): + proc = spawn_httpd("out.log") + try: + req = requests.head(f"http://{host}:{port}/index.html") + assert req.status_code == 200 + assert req.text == "" + finally: + kill_httpd(proc) + +@pytest.mark.timeout(2) +def test_missing_host(): + proc = spawn_httpd("out.log") + sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) + sock.connect((host,int(port))) + + request = f"GET /index.html HTTP/1.1\r\nConnection: close\r\n\r\n" + + sock.sendall(request.encode()) + + response = http.client.HTTPResponse(sock) + response.begin() + + try: + assert response.status == 400 + finally: + kill_httpd(proc) + +@pytest.mark.timeout(2) +def test_directory_traversal(): + proc = spawn_httpd("out.log") + sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) + sock.connect((host,int(port))) + + request = f"GET /../test_suite.py HTTP/1.1\r\nHOST: {host}:{port}\r\nConnection: close\r\n\r\n" + + sock.sendall(request.encode()) + + response = http.client.HTTPResponse(sock) + response.begin() + + try: + assert response.status in [400, 403, 404] + finally: + kill_httpd(proc) From 50891b21f24956a4c11afed41fd80582554821f2 Mon Sep 17 00:00:00 2001 From: "Gu://em_" Date: Sat, 10 Jan 2026 19:05:16 +0100 Subject: [PATCH 2/3] =?UTF-8?q?Bon=20bah=20enfin=20fini=20de=20merge=20les?= =?UTF-8?q?=203=20putains=20de=20diff=C3=A9rents=20repos=20(beauuucoup=20t?= =?UTF-8?q?rop=20de=20temps=20accord=C3=A9=20=C3=A0=20ce=20projet,=20non?= =?UTF-8?q?=20mais=20ouais=20franchement)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- httpd/src/http/headers.c | 13 ++++++++++--- httpd/src/http/http.c | 15 +++++++++++---- .../test_host_compliance.sh => tests_mieux.sh} | 0 3 files changed, 21 insertions(+), 7 deletions(-) rename httpd/tests/{test_root_dir/test_host_compliance.sh => tests_mieux.sh} (100%) diff --git a/httpd/src/http/headers.c b/httpd/src/http/headers.c index 88b64bf..ce7806c 100644 --- a/httpd/src/http/headers.c +++ b/httpd/src/http/headers.c @@ -42,6 +42,12 @@ ssize_t read_value(struct string *str, size_t offset, struct string **res) if (str->size <= offset + nread || str->data[offset + nread] != '\n') return ERR_HTTP_INVALID_INPUT; + // Trim trailing \r + if ((*res)->size > 0 && (*res)->data[(*res)->size - 1] == '\r') + { + (*res)->size--; + } + return nread; } @@ -53,7 +59,8 @@ ssize_t parse_headers(struct http_request *res, struct string *req, // Yes I know I do one useless allocation but I really don't care at this // point - while (req->data[i] != '\n' && req->data[i] != '\r') // ! Blank line + while (i < req->size && req->data[i] != '\n' + && req->data[i] != '\r') // ! Blank line { if (header == NULL) { @@ -87,9 +94,9 @@ ssize_t parse_headers(struct http_request *res, struct string *req, i += nread + 1; } - if (req->data[i] == '\r') + if (i < req->size && req->data[i] == '\r') i++; - if (req->data[i] == '\n') + if (i < req->size && req->data[i] == '\n') i++; return i; diff --git a/httpd/src/http/http.c b/httpd/src/http/http.c index 237f312..4fb2280 100644 --- a/httpd/src/http/http.c +++ b/httpd/src/http/http.c @@ -68,9 +68,15 @@ static ssize_t parse_reqline(struct http_request *res, struct string *req) return ERR_HTTP_INVALID_INPUT; i += skipped; - // CRLF (EOL) - if (req->data[i++] != '\r' && req->data[i++] != '\n') + // CRLF (EOL) oh qu'il est casse couilles celui-là + ssize_t req_size = req->size; // aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaah + if (i < req_size && req->data[i] == '\r') + i++; + if (i >= req_size || req->data[i] != '\n') return ERR_HTTP_INVALID_INPUT; + i++; + // Donc 2h de debug pour ça là ? Plutot envie de me tirer une balle si vous + // voulez mon avis return i; } @@ -184,7 +190,8 @@ static void check_req(struct http_request *req, struct http_response *resp) != 0) resp->status_code = 400; else if (string_compare_strictly_n_str(req->protocol, "HTTP/1.1", - strlen("HTTP/1.1")) != 0) + strlen("HTTP/1.1")) + != 0) resp->status_code = 505; // Host @@ -195,7 +202,7 @@ static void check_req(struct http_request *req, struct http_response *resp) while (cur != NULL) { if (cur->field->size == 4 - && string_compare_n_str(cur->field, "Host", 4) == 0) + && string_compare_n_str(cur->field, "host", 4) == 0) { host_count++; if (cur->value == NULL || cur->value->size == 0) diff --git a/httpd/tests/test_root_dir/test_host_compliance.sh b/httpd/tests/tests_mieux.sh similarity index 100% rename from httpd/tests/test_root_dir/test_host_compliance.sh rename to httpd/tests/tests_mieux.sh From df45cf75db25fc7cadedf66ec1af99bfa3f43bb3 Mon Sep 17 00:00:00 2001 From: "Gu://em_" Date: Wed, 24 Jun 2026 16:56:11 +0200 Subject: [PATCH 3/3] Changed repo organisation --- httpd/.gitignore => .gitignore | 0 httpd/Makefile => Makefile | 0 {httpd/src => src}/config/config.c | 0 {httpd/src => src}/config/config.h | 0 {httpd/src => src}/daemon/daemon.c | 0 {httpd/src => src}/daemon/daemon.h | 0 {httpd/src => src}/http/headers.c | 0 {httpd/src => src}/http/headers.h | 0 {httpd/src => src}/http/http.c | 0 {httpd/src => src}/http/http.h | 0 {httpd/src => src}/logger/errors.c | 0 {httpd/src => src}/logger/errors.h | 0 {httpd/src => src}/logger/logs.c | 0 {httpd/src => src}/logger/logs.h | 0 {httpd/src => src}/main.c | 0 {httpd/src => src}/server/server.c | 0 {httpd/src => src}/server/server.h | 0 {httpd/src => src}/utils/files/files.c | 0 {httpd/src => src}/utils/files/files.h | 0 {httpd/src => src}/utils/parsing/blanks.c | 0 {httpd/src => src}/utils/parsing/blanks.h | 0 {httpd/src => src}/utils/parsing/words.c | 0 {httpd/src => src}/utils/parsing/words.h | 0 {httpd/src => src}/utils/string/string.c | 0 {httpd/src => src}/utils/string/string.h | 0 {httpd/src => src}/utils/time/fmt_time.c | 0 {httpd/src => src}/utils/time/fmt_time.h | 0 {httpd/tests => tests}/config.txt | 0 {httpd/tests => tests}/config_reader.sh | 0 {httpd/tests => tests}/test_root_dir/index.html | 0 {httpd/tests => tests}/test_suite.py | 0 {httpd/tests => tests}/tests_mieux.sh | 0 32 files changed, 0 insertions(+), 0 deletions(-) rename httpd/.gitignore => .gitignore (100%) rename httpd/Makefile => Makefile (100%) rename {httpd/src => src}/config/config.c (100%) rename {httpd/src => src}/config/config.h (100%) rename {httpd/src => src}/daemon/daemon.c (100%) rename {httpd/src => src}/daemon/daemon.h (100%) rename {httpd/src => src}/http/headers.c (100%) rename {httpd/src => src}/http/headers.h (100%) rename {httpd/src => src}/http/http.c (100%) rename {httpd/src => src}/http/http.h (100%) rename {httpd/src => src}/logger/errors.c (100%) rename {httpd/src => src}/logger/errors.h (100%) rename {httpd/src => src}/logger/logs.c (100%) rename {httpd/src => src}/logger/logs.h (100%) rename {httpd/src => src}/main.c (100%) rename {httpd/src => src}/server/server.c (100%) rename {httpd/src => src}/server/server.h (100%) rename {httpd/src => src}/utils/files/files.c (100%) rename {httpd/src => src}/utils/files/files.h (100%) rename {httpd/src => src}/utils/parsing/blanks.c (100%) rename {httpd/src => src}/utils/parsing/blanks.h (100%) rename {httpd/src => src}/utils/parsing/words.c (100%) rename {httpd/src => src}/utils/parsing/words.h (100%) rename {httpd/src => src}/utils/string/string.c (100%) rename {httpd/src => src}/utils/string/string.h (100%) rename {httpd/src => src}/utils/time/fmt_time.c (100%) rename {httpd/src => src}/utils/time/fmt_time.h (100%) rename {httpd/tests => tests}/config.txt (100%) rename {httpd/tests => tests}/config_reader.sh (100%) rename {httpd/tests => tests}/test_root_dir/index.html (100%) rename {httpd/tests => tests}/test_suite.py (100%) rename {httpd/tests => tests}/tests_mieux.sh (100%) diff --git a/httpd/.gitignore b/.gitignore similarity index 100% rename from httpd/.gitignore rename to .gitignore diff --git a/httpd/Makefile b/Makefile similarity index 100% rename from httpd/Makefile rename to Makefile diff --git a/httpd/src/config/config.c b/src/config/config.c similarity index 100% rename from httpd/src/config/config.c rename to src/config/config.c diff --git a/httpd/src/config/config.h b/src/config/config.h similarity index 100% rename from httpd/src/config/config.h rename to src/config/config.h diff --git a/httpd/src/daemon/daemon.c b/src/daemon/daemon.c similarity index 100% rename from httpd/src/daemon/daemon.c rename to src/daemon/daemon.c diff --git a/httpd/src/daemon/daemon.h b/src/daemon/daemon.h similarity index 100% rename from httpd/src/daemon/daemon.h rename to src/daemon/daemon.h diff --git a/httpd/src/http/headers.c b/src/http/headers.c similarity index 100% rename from httpd/src/http/headers.c rename to src/http/headers.c diff --git a/httpd/src/http/headers.h b/src/http/headers.h similarity index 100% rename from httpd/src/http/headers.h rename to src/http/headers.h diff --git a/httpd/src/http/http.c b/src/http/http.c similarity index 100% rename from httpd/src/http/http.c rename to src/http/http.c diff --git a/httpd/src/http/http.h b/src/http/http.h similarity index 100% rename from httpd/src/http/http.h rename to src/http/http.h diff --git a/httpd/src/logger/errors.c b/src/logger/errors.c similarity index 100% rename from httpd/src/logger/errors.c rename to src/logger/errors.c diff --git a/httpd/src/logger/errors.h b/src/logger/errors.h similarity index 100% rename from httpd/src/logger/errors.h rename to src/logger/errors.h diff --git a/httpd/src/logger/logs.c b/src/logger/logs.c similarity index 100% rename from httpd/src/logger/logs.c rename to src/logger/logs.c diff --git a/httpd/src/logger/logs.h b/src/logger/logs.h similarity index 100% rename from httpd/src/logger/logs.h rename to src/logger/logs.h diff --git a/httpd/src/main.c b/src/main.c similarity index 100% rename from httpd/src/main.c rename to src/main.c diff --git a/httpd/src/server/server.c b/src/server/server.c similarity index 100% rename from httpd/src/server/server.c rename to src/server/server.c diff --git a/httpd/src/server/server.h b/src/server/server.h similarity index 100% rename from httpd/src/server/server.h rename to src/server/server.h diff --git a/httpd/src/utils/files/files.c b/src/utils/files/files.c similarity index 100% rename from httpd/src/utils/files/files.c rename to src/utils/files/files.c diff --git a/httpd/src/utils/files/files.h b/src/utils/files/files.h similarity index 100% rename from httpd/src/utils/files/files.h rename to src/utils/files/files.h diff --git a/httpd/src/utils/parsing/blanks.c b/src/utils/parsing/blanks.c similarity index 100% rename from httpd/src/utils/parsing/blanks.c rename to src/utils/parsing/blanks.c diff --git a/httpd/src/utils/parsing/blanks.h b/src/utils/parsing/blanks.h similarity index 100% rename from httpd/src/utils/parsing/blanks.h rename to src/utils/parsing/blanks.h diff --git a/httpd/src/utils/parsing/words.c b/src/utils/parsing/words.c similarity index 100% rename from httpd/src/utils/parsing/words.c rename to src/utils/parsing/words.c diff --git a/httpd/src/utils/parsing/words.h b/src/utils/parsing/words.h similarity index 100% rename from httpd/src/utils/parsing/words.h rename to src/utils/parsing/words.h diff --git a/httpd/src/utils/string/string.c b/src/utils/string/string.c similarity index 100% rename from httpd/src/utils/string/string.c rename to src/utils/string/string.c diff --git a/httpd/src/utils/string/string.h b/src/utils/string/string.h similarity index 100% rename from httpd/src/utils/string/string.h rename to src/utils/string/string.h diff --git a/httpd/src/utils/time/fmt_time.c b/src/utils/time/fmt_time.c similarity index 100% rename from httpd/src/utils/time/fmt_time.c rename to src/utils/time/fmt_time.c diff --git a/httpd/src/utils/time/fmt_time.h b/src/utils/time/fmt_time.h similarity index 100% rename from httpd/src/utils/time/fmt_time.h rename to src/utils/time/fmt_time.h diff --git a/httpd/tests/config.txt b/tests/config.txt similarity index 100% rename from httpd/tests/config.txt rename to tests/config.txt diff --git a/httpd/tests/config_reader.sh b/tests/config_reader.sh similarity index 100% rename from httpd/tests/config_reader.sh rename to tests/config_reader.sh diff --git a/httpd/tests/test_root_dir/index.html b/tests/test_root_dir/index.html similarity index 100% rename from httpd/tests/test_root_dir/index.html rename to tests/test_root_dir/index.html diff --git a/httpd/tests/test_suite.py b/tests/test_suite.py similarity index 100% rename from httpd/tests/test_suite.py rename to tests/test_suite.py diff --git a/httpd/tests/tests_mieux.sh b/tests/tests_mieux.sh similarity index 100% rename from httpd/tests/tests_mieux.sh rename to tests/tests_mieux.sh