Skip to content

fix(http): fix 7 security/correctness bugs + refactor HTTP layer#21

Merged
byronlove111 merged 5 commits into
mainfrom
fix/http-layer-bugs-and-refactor
Jun 17, 2026
Merged

fix(http): fix 7 security/correctness bugs + refactor HTTP layer#21
byronlove111 merged 5 commits into
mainfrom
fix/http-layer-bugs-and-refactor

Conversation

@byronlove111

Copy link
Copy Markdown
Collaborator

Summary

  • 7 bugs corrigés dans le HTTP layer (sécurité + correction + conformité sujet)
  • Refactoring complet des 9 fichiers .cpp du layer (nommage verbeux, lisibilité)
  • Tests restructurés en unit/ et integration/ + 106 nouveaux tests

Bugs corrigés

# Bug Impact
1 Path traversal GET non bloqué (root + uri sans validation) Lecture hors webroot possible
2 client_max_body_size ignoré — jamais de 413 Grille éval §2
3 Route sans match → 405 au lieu de 404 URL incorrecte → mauvais code
4 Path traversal encodé (%2e%2e) non décodé Contournement de la garde
5 PATH_INFO incluait la query string CGI reçoit un path invalide
6 write() CGI stdin sans boucle Body tronqué si > buffer kernel
7 WIFSIGNALED non vérifié après waitpid() CGI tué par signal traité comme succès

Violation hard constraint résolue

Le select() dans execute.cpp (second multiplexeur I/O) a été remplacé par O_NONBLOCK + time() — la codebase a maintenant exactement un seul appel poll/select/epoll/kqueue (dans le futur core server).

Tests

  • tests/http/unit/ — 67 tests (RequestParser, ResponseBuilder, Router) — 0 I/O disque
  • tests/http/integration/ — 197 tests (GET/POST/DELETE handlers, CGI basique, CGI avancé, adversarial)
  • 221 tests total, 0 échec

Checklist

  • Zéro select()/poll()/epoll()/kqueue() dans src/
  • fork() uniquement dans cgi/execute.cpp
  • fcntl() uniquement avec F_SETFL + O_NONBLOCK
  • Zéro errno après read/write/recv/send
  • C++98 strict — zero auto, nullptr, lambdas, range-for
  • Compilation -Wall -Wextra -Werror -std=c++98 sans warning

Made with Cursor

byronlove111 and others added 5 commits June 17, 2026 15:54
…ayer

Security fixes:
- Centralize path traversal guard in MethodHandler::handle() — covers GET,
  POST, DELETE and CGI before any dispatch
- Add urlDecode() to detect encoded variants (%2e%2e, %2f, etc.)

Correctness fixes:
- Return 404 when no location matches (was 405)
- Enforce client_max_body_size → 413 Payload Too Large
- Fix PATH_INFO to strip query string before passing to CGI
- Replace single write() with loop for CGI stdin (prevents body truncation)
- Handle WIFSIGNALED in CGI exit status check
- Remove second select() in CGI timeout — replaced with O_NONBLOCK + time()
  to keep exactly one poll() multiplexer in the codebase

Refactoring:
- Rename all short variables (req→request, loc→location, fd→fileDescriptor,
  st→fileInfo, ss→contentLength, n→bytesRead, etc.) across all 9 HTTP files
- Extract intermediate boolean variables to document intent
- Remove scattered hasPathTraversal() copies from PostHandler/DeleteHandler

Tests:
- Restructure tests/http/ into unit/ and integration/ subdirectories
- Add test_adversarial.cpp: 48 tests covering parsing attacks, path traversal
  (including encoded variants), method attacks, router edge cases, full pipeline
- Add test_cgi_advanced.cpp: 58 tests covering env vars, POST body, query
  strings, custom status codes, large output (100KB), error handling (404/500/
  403/stderr/timeout), full pipeline eval-style scenarios
- Add 10 advanced Python CGI scripts for integration testing

Co-authored-by: Cursor <cursoragent@cursor.com>
std::string(const char*) stops at the first \0, so raw.find('\0')
returns npos and raw[npos] is an out-of-bounds write. On macOS/clang
this passes silently; on Ubuntu/glibc it triggers 'double free or
corruption' and aborts.

Fix: use the length-based std::string(buf, len) constructor so the
embedded \0 is actually included in the string.

Co-authored-by: Cursor <cursoragent@cursor.com>
MethodHandler.cpp : isMethodAllowed + buildError avant handle()
RequestParser.cpp : isValid + parseFirstLine + parseHeaders + parseBody avant parse()
output.cpp        : buildError avant parseOutput()

Co-authored-by: Cursor <cursoragent@cursor.com>
…rror

MethodHandler::buildError et CgiHandler::buildError \u00e9taient identiques.
Extrait en fonction libre buildHttpError() dans HttpUtils.hpp/.cpp.
Supprim\u00e9 des deux classes, tous les appels mis \u00e0 jour.

Co-authored-by: Cursor <cursoragent@cursor.com>
StringUtils.hpp/.cpp : urlDecode, hasPathTraversal, extractQueryString, extractFilename
HttpUtils.hpp/.cpp   : buildHttpError, getContentType

Supprime les fonctions statiques dupliquees dans chaque handler/cgi.
Ancien HttpUtils a la racine remplace par include/http/utils/ et src/http/utils/.

Co-authored-by: Cursor <cursoragent@cursor.com>
@byronlove111 byronlove111 merged commit 964e9e3 into main Jun 17, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant