Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
157 commits
Select commit Hold shift + click to select a range
14188fa
TASK-001: Bump C++ standard floor to C++20
etr Apr 30, 2026
5288ecd
Merge TASK-001: Bump C++ standard floor to C++20
etr Apr 30, 2026
638c26a
Ignore .groundwork-plans/
etr Apr 30, 2026
c80fdff
TASK-002: Lock public/private header surface and inclusion gates
etr Apr 30, 2026
48a8835
Merge TASK-002: Public/private header layout and inclusion guards
etr Apr 30, 2026
243ec8f
Fix CI: drop C++20-incompatible compilers and add libmicrohttpd-devel…
etr May 1, 2026
5b78014
Fix MSYS/Cygwin build: expose _DEFAULT_SOURCE for libmicrohttpd's fd_…
etr May 1, 2026
b9ef39d
Fix CI follow-up: add LGPL header to gate tests, drop ubuntu-toolchai…
etr May 1, 2026
6b87fea
TASK-003: Add httpserver::feature_unavailable exception type
etr May 1, 2026
a05f79c
Merge TASK-003: Add httpserver::feature_unavailable exception type
etr May 1, 2026
74c1726
TASK-004: Add httpserver::iovec_entry POD with layout-pinning asserts
etr May 1, 2026
259b4bb
TASK-004: fix use-after-free in copy ctor, header hygiene, test impro…
etr May 1, 2026
d2a2544
Merge TASK-004: Add httpserver::iovec_entry POD with layout-pinning a…
etr May 2, 2026
03533c6
TASK-005: Add http_method enum and method_set bitmask
etr May 2, 2026
a3ec719
Merge TASK-005: Add http_method enum and method_set bitmask
etr May 2, 2026
71bf2a2
TASK-006: Replace #define constants with httpserver::constants
etr May 3, 2026
c93ee31
TASK-006: housekeeping (status + checkboxes)
etr May 3, 2026
0e0d001
TASK-006: housekeeping (mark task complete in index)
etr May 3, 2026
7c2f460
Merge TASK-006: Replace #define constants with httpserver::constants
etr May 3, 2026
6018559
TASK-007: CI test for public-header hygiene
etr May 3, 2026
f3c0292
TASK-007: share staged install across check-local; skip make check on…
etr May 3, 2026
064b7fc
Merge TASK-007: CI test for public-header hygiene
etr May 3, 2026
1228e20
TASK-007: housekeeping (mark task complete in index)
etr May 3, 2026
13f0818
TASK-008: Internal detail::body hierarchy
etr May 3, 2026
828006c
TASK-008: review-pass fixes (security + performance iter1)
etr May 3, 2026
d206af5
Merge TASK-008: Internal detail::body hierarchy
etr May 3, 2026
454e3d4
TASK-008: housekeeping (mark task complete in index)
etr May 3, 2026
6388623
specs: add planning scaffolding and review records
etr May 3, 2026
c05e355
Fix CI: -Werror=type-limits and accumulated cpplint errors
etr May 3, 2026
098759d
Fix CI: gate POSIX struct iovec asserts on !_WIN32
etr May 3, 2026
13aa17a
Fix CI: gate iovec_entry_test struct iovec bridge on !_WIN32
etr May 3, 2026
c953e85
Fix CI: gate pipe_body tests on !_WIN32
etr May 3, 2026
f4bb3d2
TASK-009: http_response value type with SBO buffer + detail/ rename
etr May 3, 2026
146c85d
TASK-009: review-pass fixes (code-quality iter2: details→detail names…
etr May 3, 2026
eb1d233
TASK-009: housekeeping (status + checkboxes + arch doc syncs)
etr May 3, 2026
2af5e36
Merge TASK-009: http_response value type with SBO buffer + detail/ re…
etr May 3, 2026
798fa38
TASK-009 follow-up: forward-task spec edits (TASK-010, TASK-013)
etr May 3, 2026
8fa2c6b
TASK-010: http_response static factory functions
etr May 3, 2026
e997866
TASK-010: review-pass fixes (security: WWW-Authenticate header inject…
etr May 3, 2026
d497e50
TASK-010: housekeeping (status + checkboxes + review record)
etr May 3, 2026
21f1ab8
Merge TASK-010: http_response factory functions
etr May 3, 2026
0d0ea3d
TASK-011: http_response const-correct accessors
etr May 3, 2026
b7d9138
TASK-011: housekeeping (status + checkboxes + review records)
etr May 3, 2026
07af54a
Merge TASK-011: http_response const-correct accessors
etr May 3, 2026
81ab57a
TASK-012: http_response fluent with_* setters
etr May 3, 2026
fc0a773
TASK-012: review-pass fixes (security: header injection / simplify: &…
etr May 3, 2026
529d945
TASK-012: record unworked review issues from validation pass
etr May 3, 2026
67db6a4
Merge TASK-012: http_response fluent with_* setters
etr May 3, 2026
f4a5530
TASK-013: remove v1 *_response subclasses, seal http_response
etr May 3, 2026
fff3d62
TASK-013: review-pass fixes (DRY forbidden-char constant, dispatch nu…
etr May 4, 2026
98f6a2f
TASK-013: housekeeping (status + checkboxes + arch sync + review record)
etr May 4, 2026
ce14c7b
Merge TASK-013: remove v1 *_response subclasses and seal http_response
etr May 4, 2026
dea9c63
TASK-014: webserver_impl skeleton (PIMPL prep, structural only)
etr May 4, 2026
1b14dd1
TASK-014: housekeeping (status In Progress + index sync + review record)
etr May 4, 2026
369c2a8
Merge TASK-014: webserver_impl skeleton (PIMPL prep, structural only)
etr May 4, 2026
e9175c1
TASK-015: http_request_impl skeleton (PIMPL split, structural only)
etr May 4, 2026
fd6c984
TASK-015: wire test-request fallback through http_request_impl
etr May 4, 2026
01c425b
TASK-015: housekeeping (review record)
etr May 4, 2026
707bfbc
Merge TASK-015: http_request_impl skeleton (PIMPL split, structural o…
etr May 4, 2026
f57312c
TASK-016: per-connection arena for http_request_impl
etr May 4, 2026
f6ade0e
TASK-016: review-pass fixes (security, perf, tests)
etr May 4, 2026
1f0c04a
TASK-016: housekeeping (status Done + checkboxes + review records)
etr May 4, 2026
54cfe91
Merge TASK-016: per-connection arena for http_request_impl
etr May 4, 2026
fa1b9dd
TASK-017: http_request container getters return const&
etr May 4, 2026
6352488
TASK-017: housekeeping (review records)
etr May 5, 2026
6d73c15
Merge TASK-017: http_request container getters return const&
etr May 5, 2026
ea10882
Fix CI: cpplint cleanup and create_test_request method uppercase
etr May 5, 2026
cd15cfb
TASK-018: http_request single-key getters return string_view, all const
etr May 6, 2026
3ec2f6d
TASK-018: housekeeping (status Done + checkboxes + review records)
etr May 6, 2026
57717ea
Merge TASK-018: http_request single-key getters return string_view, a…
etr May 6, 2026
12970e2
TASK-019: high-level GnuTLS accessors replacing gnutls_session_t
etr May 6, 2026
d0aaaa2
TASK-019: housekeeping (status Done + checkboxes + review records)
etr May 7, 2026
a97f06d
Merge TASK-019: high-level GnuTLS accessors replacing gnutls_session_t
etr May 7, 2026
33ae023
TASK-020: flip header-hygiene gates to strict mode (TDD red)
etr May 7, 2026
0f3655f
TASK-020: sweep backend includes from public headers (TDD green)
etr May 7, 2026
ecfcdfa
TASK-020: housekeeping (_index status Done + review record)
etr May 7, 2026
b94be89
Merge TASK-020: final public-header backend-include sweep
etr May 7, 2026
0bfbe85
codacy: silence pimpl false positives, fix cstyleCast/knownConditionT…
etr May 7, 2026
0d82a50
Fix header_hygiene CI: skip pthread guards on libstdc++ in thread mode
etr May 7, 2026
d2e137f
Fix CI: cpplint include order in http_utils.cpp + Windows ERROR macro…
etr May 7, 2026
d383a4e
TASK-021: http_resource allow-mask via method_set
etr May 7, 2026
6a0dcb1
TASK-021: validation fixes (count_ sentinel guard + behavior-based test)
etr May 7, 2026
8da6215
Merge TASK-021: http_resource allow-mask via method_set
etr May 7, 2026
ea276cc
TASK-022: snake_case render_* overrides on http_resource
etr May 9, 2026
22f1c02
TASK-022: housekeeping — mark Done, record unworked review issues
etr May 9, 2026
4bd6036
Merge TASK-022: snake_case render_* overrides on http_resource
etr May 9, 2026
003f37e
TASK-023: failing tests for smart-pointer register_resource overloads…
etr May 10, 2026
7f2e86f
TASK-023: smart-pointer register_resource overloads (GREEN)
etr May 10, 2026
beaaf80
TASK-023: housekeeping — mark Done, record unworked review issues
etr May 10, 2026
a30a307
Merge TASK-023: smart-pointer register_resource overloads
etr May 10, 2026
7d7146b
TASK-024: failing tests for register_path/register_prefix split (RED)
etr May 10, 2026
d23d1a5
TASK-024: register_path / register_prefix split (GREEN)
etr May 10, 2026
b722066
TASK-024: housekeeping — mark Done
etr May 10, 2026
12b99b6
TASK-024: close unregister_resource TOCTOU race, record unworked revi…
etr May 10, 2026
744187f
Merge TASK-024: register_path / register_prefix split
etr May 10, 2026
4726527
test(TASK-025): RED on_* lambda registration suite
etr May 10, 2026
9daf303
feat(TASK-025): GREEN seven on_* lambda registration entry points
etr May 10, 2026
f8f6062
TASK-025: mark action items checked (status: In Progress)
etr May 10, 2026
c17dce7
TASK-025: validation fixes — per-method tests, assert(slot), housekee…
etr May 10, 2026
39c3c0d
Merge TASK-025: Lambda handler entry points on_*
etr May 10, 2026
336f1a9
test(TASK-026): RED route() generic registration suite
etr May 10, 2026
022bbbf
feat(TASK-026): GREEN route() / route(method_set) registration entry …
etr May 10, 2026
ceb1ada
TASK-026: mark action items checked (status: In Progress)
etr May 10, 2026
c1f1f25
TASK-026: housekeeping — mark Done, record unworked review issues
etr May 10, 2026
fd8b090
Merge TASK-026: Generic webserver::route(method, path, handler)
etr May 10, 2026
c56c654
TASK-014: housekeeping — promote status from In Progress to Done
etr May 10, 2026
90b8015
TASK-006/007/015: housekeeping — normalize status to Done
etr May 10, 2026
ee4a782
TASK-027: 3-tier route table (hash + radix + regex) with LRU cache
etr May 10, 2026
4cbbe1d
TASK-027: validation fixes — pre-compiled regex tier, classify_route_…
etr May 10, 2026
370093d
Merge TASK-027: 3-tier route table (hash + radix + regex) with LRU cache
etr May 10, 2026
71c9b5a
TASK-028: routing-semantics regression gate
etr May 10, 2026
ab89977
TASK-028: validation fixes — cache-tier pins, miss baseline, _index Done
etr May 10, 2026
cf31239
Merge TASK-028: routing-semantics regression gate
etr May 10, 2026
ec82d90
TASK-029: collapse IP-control and stop verbs to canonical names
etr May 11, 2026
87c871a
TASK-029: validation fixes — housekeeping (status Done, unworked find…
etr May 11, 2026
f015eba
Merge TASK-029: naming consistency — stop_and_wait, block_ip/unblock_ip
etr May 11, 2026
afbef79
TASK-029: housekeeping — prune false-positive findings, normalize paths
etr May 11, 2026
bab42b8
ci: clear Codacy new-issue set on the v2.0 PR
etr May 11, 2026
f2f1aea
ci: also exclude top-level test/*.md from Codacy
etr May 11, 2026
beb0811
TASK-030: _handler suffix renames + explicit webserver ctor
etr May 11, 2026
bbdcf56
TASK-030: mark task In Progress in index and task file
etr May 11, 2026
df3fa9a
TASK-030: validation fixes — housekeeping (status Done, unworked find…
etr May 11, 2026
908f5c2
Merge TASK-030: `_handler` suffix renames + `explicit` constructor
etr May 11, 2026
b40b00e
TASK-031: implement DR-009 handler error-propagation contract
etr May 11, 2026
ea63ffe
TASK-031: validation fixes — housekeeping (status Done, unworked find…
etr May 11, 2026
2f7b4ea
Merge TASK-031: Handler error-propagation contract (DR-009)
etr May 11, 2026
0acbbf7
TASK-032: DR-008 thread-safety contract stress test
etr May 11, 2026
5aa69d6
TASK-032: validation fixes — housekeeping (status Done, unworked find…
etr May 11, 2026
e7f14c7
Merge TASK-032: Thread-safety contract stress test (DR-008)
etr May 11, 2026
c605ee4
TASK-033: create_webserver builder cleanup (PRD-CFG-REQ-001..004)
etr May 11, 2026
a92ff88
TASK-033: validation fixes — housekeeping (status Done, unworked find…
etr May 14, 2026
3832d3b
Merge TASK-033: create_webserver builder cleanup (PRD-CFG-REQ-001..004)
etr May 14, 2026
8fd0743
TASK-034: build-flag-independent public API + webserver::features()
etr May 14, 2026
99be8c2
TASK-034: validation fixes — security (HAVE_DAUTH guard + test-reques…
etr May 14, 2026
8b4ed30
TASK-034: record unworked validation findings (5 major, 27 minor)
etr May 14, 2026
2c15687
Merge TASK-034: Build-flag-independent public API + webserver::featur…
etr May 18, 2026
ce4e028
TASK-035: smart-pointer register_ws_resource overloads
etr May 18, 2026
5ce53f2
TASK-035: record unworked validation findings (1 major, 19 minor)
etr May 18, 2026
973d96c
Merge TASK-035: Smart-pointer register_ws_resource overloads (PRD-HDL…
etr May 18, 2026
25a53c7
TASK-036: handler return-by-value dispatch cutover
etr May 18, 2026
ef2623a
TASK-036: record unworked validation findings (12 major, 41 minor)
etr May 19, 2026
516e1ab
Merge TASK-036: Handler return-by-value dispatch cutover (PRD-HDL-REQ…
etr May 19, 2026
49f18bd
TASK-037: CI build-flag invariance gate
etr May 19, 2026
9726137
TASK-037: validation fixes — security (read-only GITHUB_TOKEN + SHA-2…
etr May 19, 2026
dbf484b
TASK-037: record unworked validation findings (3 major, 30 minor)
etr May 19, 2026
348699b
Merge TASK-037: CI test for build-flag invariance (PRD-FLG-REQ-001, a…
etr May 19, 2026
6965bba
TASK-038: sanitizer-clean http_response move-semantics test + CI sani…
etr May 19, 2026
a216ec7
TASK-038: mark Done in task index and record unworked validation find…
etr May 19, 2026
c71b0e8
Merge TASK-038: Sanitizer-clean tests for http_response move semantic…
etr May 19, 2026
5bf5b65
TASK-039: Performance acceptance gates for get_headers and sizeof(htt…
etr May 19, 2026
443d943
TASK-039: validation fixes — performance methodology
etr May 19, 2026
a2a7705
TASK-039: record unworked validation findings (4 major, 36 minor)
etr May 19, 2026
9a8f077
Merge TASK-039: Performance acceptance gates for get_headers and size…
etr May 19, 2026
1ea42cb
TASK-040: Rewrite examples/ for the v2.0 lambda-first idiom
etr May 19, 2026
dfe2a8f
TASK-040: validation fixes — examples and scripts
etr May 19, 2026
f9b582e
TASK-040: record unworked validation findings (1 major, 81 minor)
etr May 19, 2026
68c3d6a
Merge TASK-040: Rewrite examples/ for the v2.0 lambda-first idiom (PR…
etr May 19, 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
13 changes: 13 additions & 0 deletions .codacy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
# Codacy project configuration.
#
# specs/ holds internal groundwork artifacts (product specs, architecture
# notes, task records, review notes). They are not user-facing docs and are
# not subject to the same markdown style as README/ChangeLog/CONTRIBUTING.
#
# test/*.md are internal test-suite documents (e.g. the v2.0 routing
# regression gate at test/REGRESSION.md). Same rationale as specs/.
exclude_paths:
- 'specs/**'
- 'test/*.md'
- 'test/**/*.md'
268 changes: 188 additions & 80 deletions .github/workflows/verify-build.yml

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,5 @@ libtool
.worktrees
.claude
CLAUDE.md
.groundwork-plans/
.DS_Store
15 changes: 15 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
Version 0.20.0

Raised minimum C++ standard to C++20. Build now requires gcc >= 10
or clang >= 13 (Apple Clang from Xcode 15+). Updated
AX_CXX_COMPILE_STDCXX macro (m4/ax_cxx_compile_stdcxx.m4) to
serial 25 to support C++20 detection. Pruned CI matrix rows
(gcc-9, clang-11, clang-12) that lack full C++20 support.
Raised minimum libmicrohttpd requirement to 1.0.0.
Migrated Basic Auth to v3 API (MHD_basic_auth_get_username_password3,
MHD_queue_basic_auth_required_response3) with UTF-8 support.
Expand All @@ -20,6 +25,16 @@ Version 0.20.0
suppress_date_header.
Added WebSocket support (conditional on HAVE_WEBSOCKET):
websocket_handler, websocket_session, register_ws_resource().
TASK-035: replaced the raw-pointer
register_ws_resource(string, websocket_handler*) overload with
smart-pointer overloads register_ws_resource(string,
unique_ptr<websocket_handler>) and register_ws_resource(string,
shared_ptr<websocket_handler>); added unregister_ws_resource(string).
Mirrors the TASK-023 register_resource ownership model and is
consistent with DR-010 / PRD-HDL-REQ-003 / PRD-HDL-REQ-005.
Duplicate registrations now throw std::invalid_argument
(previously a silent overwrite). On HAVE_WEBSOCKET-off builds
all three entry points throw feature_unavailable.
Added utility functions: reason_phrase(), is_feature_supported(),
get_mhd_version().
Added example and documentation for serving binary data from memory
Expand Down
280 changes: 279 additions & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,289 @@ endif

endif

EXTRA_DIST = libhttpserver.pc.in $(DX_CONFIG) scripts/extract-release-notes.sh scripts/validate-version.sh
EXTRA_DIST = libhttpserver.pc.in $(DX_CONFIG) scripts/extract-release-notes.sh scripts/validate-version.sh \
scripts/check-examples.sh scripts/verify-installed-examples.sh \
test/headers/consumer_direct.cpp test/headers/consumer_detail.cpp test/headers/consumer_umbrella.cpp \
test/headers/consumer_post_umbrella.cpp \
test/headers/consumer_umbrella_no_backend.cpp

# ---------------------------------------------------------------------------
# Header-hygiene checks (TASK-002)
#
# check-headers verifies that the public/private header gates are wired up
# correctly:
# A.1 a consumer including a public header WITHOUT the umbrella must hit the
# inclusion-gate #error.
# A.2 a consumer including a detail header WITHOUT HTTPSERVER_COMPILATION
# must hit the gate.
# A.3 a consumer including only the umbrella, WITHOUT HTTPSERVER_COMPILATION,
# must compile cleanly.
#
# The CXX invocations below override CXXFLAGS to '' so that
# -DHTTPSERVER_COMPILATION (injected by configure.ac into CXXFLAGS for the
# library and test build) does NOT leak into the consumer-style compile. We
# still pass -std=c++20 explicitly because libhttpserver requires C++20.
# ---------------------------------------------------------------------------

# Compose CXX with: explicit -std, the source/build include search paths used by
# the library, and $(CPPFLAGS) (e.g., -I/opt/homebrew/include from configure).
# Deliberately omit $(CXXFLAGS), $(AM_CPPFLAGS), and any per-target CPPFLAGS so
# that -DHTTPSERVER_COMPILATION (set in src/ and test/ AM_CPPFLAGS) cannot
# leak into the consumer-style compile. A true consumer never has that macro.
CHECK_HEADERS_CXX = $(CXX) -std=c++20 -I$(top_builddir) -I$(top_srcdir)/src -I$(top_srcdir)/src/httpserver $(CPPFLAGS)
CHECK_HEADERS_GATE_MSG = Only <httpserver.hpp> or <httpserverpp> can be included directly

check-headers:
@echo "=== check-headers A.1: direct public-header include must fail ==="
@if $(CHECK_HEADERS_CXX) -c $(top_srcdir)/test/headers/consumer_direct.cpp -o /dev/null 2>check-headers-A1.log; then \
echo "FAIL: consumer_direct.cpp compiled but should have errored"; \
cat check-headers-A1.log; \
rm -f check-headers-A1.log; \
exit 1; \
fi
@if ! grep -q "$(CHECK_HEADERS_GATE_MSG)" check-headers-A1.log; then \
echo "FAIL: consumer_direct.cpp failed but not for the gate reason"; \
cat check-headers-A1.log; \
rm -f check-headers-A1.log; \
exit 1; \
fi
@rm -f check-headers-A1.log
@echo " PASS: A.1 gate fired as expected"
@echo "=== check-headers A.2: direct detail-header include must fail ==="
@if $(CHECK_HEADERS_CXX) -c $(top_srcdir)/test/headers/consumer_detail.cpp -o /dev/null 2>check-headers-A2.log; then \
echo "FAIL: consumer_detail.cpp compiled but should have errored"; \
cat check-headers-A2.log; \
rm -f check-headers-A2.log; \
exit 1; \
fi
@if ! grep -q "$(CHECK_HEADERS_GATE_MSG)" check-headers-A2.log; then \
echo "FAIL: consumer_detail.cpp failed but not for the gate reason"; \
cat check-headers-A2.log; \
rm -f check-headers-A2.log; \
exit 1; \
fi
@rm -f check-headers-A2.log
@echo " PASS: A.2 gate fired as expected"
@echo "=== check-headers A.3: umbrella include must succeed ==="
@if ! $(CHECK_HEADERS_CXX) -c $(top_srcdir)/test/headers/consumer_umbrella.cpp -o consumer_umbrella.check.o 2>check-headers-A3.log; then \
echo "FAIL: consumer_umbrella.cpp did not compile"; \
cat check-headers-A3.log; \
rm -f check-headers-A3.log consumer_umbrella.check.o; \
exit 1; \
fi
@rm -f check-headers-A3.log consumer_umbrella.check.o
@echo " PASS: A.3 umbrella compiled cleanly"
@echo "=== check-headers A.4: post-umbrella direct include must fail ==="
@if $(CHECK_HEADERS_CXX) -c $(top_srcdir)/test/headers/consumer_post_umbrella.cpp -o /dev/null 2>check-headers-A4.log; then \
echo "FAIL: consumer_post_umbrella.cpp compiled but should have errored"; \
cat check-headers-A4.log; \
rm -f check-headers-A4.log; \
exit 1; \
fi
@if ! grep -q "$(CHECK_HEADERS_GATE_MSG)" check-headers-A4.log; then \
echo "FAIL: consumer_post_umbrella.cpp failed but not for the gate reason"; \
cat check-headers-A4.log; \
rm -f check-headers-A4.log; \
exit 1; \
fi
@rm -f check-headers-A4.log
@echo " PASS: A.4 umbrella does not leak _HTTPSERVER_HPP_INSIDE_"

# check-install-layout asserts that `make install DESTDIR=$(STAGE)` produces
# a public include tree with NO `detail/` directory and NO `*_impl.hpp` files.
# This protects the public/private split as described in TASK-002 / DR-002.
CHECK_INSTALL_STAGE = $(abs_top_builddir)/.install-stage

check-install-layout:
@echo "=== check-install-layout: staged install must hide detail/ and *_impl.hpp ==="
@if test "$(CHECK_INSTALL_SHARED)" != "yes"; then \
rm -rf $(CHECK_INSTALL_STAGE); \
$(MAKE) $(AM_MAKEFLAGS) install DESTDIR=$(CHECK_INSTALL_STAGE) >check-install.log 2>&1 || { \
echo "FAIL: staged install failed"; \
cat check-install.log; \
rm -f check-install.log; \
rm -rf $(CHECK_INSTALL_STAGE); \
exit 1; \
}; \
rm -f check-install.log; \
fi
@leaked_detail=`find $(CHECK_INSTALL_STAGE) -type d -name detail 2>/dev/null`; \
if test -n "$$leaked_detail"; then \
echo "FAIL: detail/ directory leaked into install:"; \
echo "$$leaked_detail"; \
if test "$(CHECK_INSTALL_SHARED)" != "yes"; then rm -rf $(CHECK_INSTALL_STAGE); fi; \
exit 1; \
fi
@leaked_impl=`find $(CHECK_INSTALL_STAGE) -name '*_impl.hpp' 2>/dev/null`; \
if test -n "$$leaked_impl"; then \
echo "FAIL: *_impl.hpp file leaked into install:"; \
echo "$$leaked_impl"; \
if test "$(CHECK_INSTALL_SHARED)" != "yes"; then rm -rf $(CHECK_INSTALL_STAGE); fi; \
exit 1; \
fi
@umbrella_count=`find $(CHECK_INSTALL_STAGE) -name 'httpserver.hpp' | wc -l | tr -d ' '`; \
if test "$$umbrella_count" != "1"; then \
echo "FAIL: expected exactly 1 installed httpserver.hpp, got $$umbrella_count"; \
if test "$(CHECK_INSTALL_SHARED)" != "yes"; then rm -rf $(CHECK_INSTALL_STAGE); fi; \
exit 1; \
fi
@if test "$(CHECK_INSTALL_SHARED)" != "yes"; then rm -rf $(CHECK_INSTALL_STAGE); fi
@echo " PASS: staged install layout is clean"

# ---------------------------------------------------------------------------
# Header-hygiene preprocessor gate (TASK-007).
#
# This is the preprocessor-grep half of the TASK-007 enforcement (the
# compile-time half lives as `header_hygiene` in test/Makefile.am).
#
# Procedure:
# 1. Stage `make install DESTDIR=$(CHECK_HYGIENE_STAGE)` to get a
# pristine public include tree -- exactly what packagers and
# downstream consumers see.
# 2. Preprocess test/headers/consumer_umbrella_no_backend.cpp using
# ONLY -I$(CHECK_HYGIENE_STAGE)$(includedir) plus $(CPPFLAGS) (so
# e.g. /opt/homebrew/include is on the search path -- the grep
# below NEEDS to resolve <microhttpd.h> if the umbrella pulls it
# in, otherwise we couldn't detect the leak).
# 3. Grep the cpp output for `# <line> "<file>"` line markers that
# name any forbidden backend header. The line-marker filter
# avoids false positives from substrings in code or comments.
#
# HEADER_HYGIENE_STRICT controls whether a leak is fatal:
# - "yes" (default since TASK-020): leaks fail the build. The umbrella
# is now clean and any regression should break CI loudly.
# - "no" (legacy): leaks were reported as EXPECTED-FAIL and exit 0
# while M2-M5 were in flight. Override from the command line
# (`make check-hygiene HEADER_HYGIENE_STRICT=no`) only if you
# are deliberately running against an in-flight umbrella.
#
# Cross-reference: keep HEADER_HYGIENE_FORBIDDEN in sync with the
# #ifdef ladder in test/unit/header_hygiene_test.cpp.
#
# TASK-020 caveat (libc++ AND libstdc++ in thread mode): <pthread.h>
# is intentionally absent from the forbidden list below. Both
# mainstream STLs unconditionally pull <pthread.h> in from any STL
# container header (<vector>, <string>, <map>, etc.) when threading
# is enabled:
# - libc++ (Apple's default STL on macOS) routes through
# <__thread/support/pthread.h>.
# - libstdc++ in thread-enabled mode (which is the default whenever
# -D_REENTRANT is set, as configure.ac does) routes through
# <bits/gthr-default.h>, which #include <pthread.h> directly.
# The resulting `# N "...pthread.h"` line markers therefore appear in
# the preprocessed output even though libhttpserver itself does not
# include <pthread.h>. The runtime sentinel
# test/unit/header_hygiene_test.cpp keeps the pthread guards but skips
# them on both libc++ (_LIBCPP_VERSION) and libstdc++ in thread mode
# (_GLIBCXX_HAS_GTHREADS), so the guards still fire on STLs that don't
# route std::thread through pthread (e.g. MSVC's Microsoft STL).
# ---------------------------------------------------------------------------

HEADER_HYGIENE_FORBIDDEN = microhttpd\.h|gnutls/gnutls\.h|sys/socket\.h|sys/uio\.h
CHECK_HYGIENE_STAGE = $(abs_top_builddir)/.hygiene-stage
CHECK_HYGIENE_CXX = $(CXX) -std=c++20 -E -I$(CHECK_HYGIENE_STAGE)$(includedir) $(CPPFLAGS)
HEADER_HYGIENE_STRICT ?= yes

# Sentinel file: only re-run the staged install when headers have changed.
# This is an mtime gate used exclusively for standalone `make check-hygiene`
# invocations — it avoids paying a full `make install` cost on every
# repeated standalone run. When check-local drives check-hygiene it sets
# CHECK_HYGIENE_SHARED=yes and passes CHECK_HYGIENE_STAGE pointing at its
# own pre-built shared stage, so this stamp target is bypassed entirely.
HYGIENE_STAMP = $(CHECK_HYGIENE_STAGE)/.hygiene-stamp

$(HYGIENE_STAMP): $(wildcard $(top_srcdir)/src/httpserver/*.hpp)
@rm -rf $(CHECK_HYGIENE_STAGE)
@$(MAKE) $(AM_MAKEFLAGS) install DESTDIR=$(CHECK_HYGIENE_STAGE) >check-hygiene-install.log 2>&1 || { \
echo "FAIL: staged install failed"; cat check-hygiene-install.log; \
rm -f check-hygiene-install.log; rm -rf $(CHECK_HYGIENE_STAGE); exit 1; }
@rm -f check-hygiene-install.log
@touch $(HYGIENE_STAMP)

check-hygiene:
@echo "=== check-hygiene: <httpserver.hpp> must not transitively include backend headers ==="
@if test "$(CHECK_HYGIENE_SHARED)" != "yes"; then \
$(MAKE) $(AM_MAKEFLAGS) $(HYGIENE_STAMP); \
else \
if ! test -d "$(CHECK_HYGIENE_STAGE)"; then \
echo "FAIL: CHECK_HYGIENE_SHARED=yes but stage dir '$(CHECK_HYGIENE_STAGE)' does not exist."; \
echo " Always pair CHECK_HYGIENE_SHARED=yes with CHECK_HYGIENE_STAGE=<valid-dir>."; \
exit 1; \
fi; \
fi
@status=0; \
if ! $(CHECK_HYGIENE_CXX) $(top_srcdir)/test/headers/consumer_umbrella_no_backend.cpp >check-hygiene.i 2>check-hygiene.err; then \
if test "$(HEADER_HYGIENE_STRICT)" = "yes"; then \
echo "FAIL: preprocessor failed"; cat check-hygiene.err; \
status=1; \
else \
echo "EXPECTED-FAIL (informational until M5): preprocessor failed against staged install."; \
echo " This is expected while M2-M5 are in flight (e.g. webserver.hpp still"; \
echo " references private detail headers that aren't shipped)."; \
echo " Tail of preprocessor diagnostics:"; \
sed 's/^/ /' check-hygiene.err | tail -10; \
fi; \
else \
leaks=`grep -hE '^# [0-9]+ "[^"]*/($(HEADER_HYGIENE_FORBIDDEN))"' check-hygiene.i | awk '{print $$3}' | sort -u`; \
if test -n "$$leaks"; then \
if test "$(HEADER_HYGIENE_STRICT)" = "yes"; then \
echo "FAIL: forbidden headers leaked through <httpserver.hpp>:"; \
echo "$$leaks"; \
status=1; \
else \
echo "EXPECTED-FAIL (informational until M5): forbidden headers currently leak through <httpserver.hpp>:"; \
echo "$$leaks"; \
fi; \
else \
echo " PASS: no forbidden headers reached the consumer TU"; \
fi; \
fi; \
rm -f check-hygiene.i check-hygiene.err; \
exit $$status

# check-local runs check-install-layout and check-hygiene against a single
# shared staged install to avoid paying two full `make install` costs on
# every `make check`. Both sub-checks can still be invoked standalone (they
# will do their own install when CHECK_*_SHARED is not set).
check-local: check-headers check-examples
@echo "=== Shared staged install for check-install-layout and check-hygiene ==="
@rm -rf $(abs_top_builddir)/.shared-check-stage
@$(MAKE) $(AM_MAKEFLAGS) install DESTDIR=$(abs_top_builddir)/.shared-check-stage >check-shared-install.log 2>&1 || { \
echo "FAIL: shared staged install failed"; cat check-shared-install.log; \
rm -f check-shared-install.log; rm -rf $(abs_top_builddir)/.shared-check-stage; exit 1; }
@rm -f check-shared-install.log
@$(MAKE) $(AM_MAKEFLAGS) check-install-layout \
CHECK_INSTALL_STAGE=$(abs_top_builddir)/.shared-check-stage \
CHECK_INSTALL_SHARED=yes
@$(MAKE) $(AM_MAKEFLAGS) check-hygiene \
CHECK_HYGIENE_STAGE=$(abs_top_builddir)/.shared-check-stage \
CHECK_HYGIENE_SHARED=yes
@rm -rf $(abs_top_builddir)/.shared-check-stage

# TASK-040: enforce static invariants on the two flagship examples
# (hello_world.cpp <= 10 LOC, lambda-only; shared_state.cpp class+mutex).
# Run as part of `make check` via check-local.
check-examples:
@echo "=== check-examples: enforce TASK-040 invariants on examples/ ==="
@$(top_srcdir)/scripts/check-examples.sh

.PHONY: check-headers check-install-layout check-hygiene check-examples

# TASK-039: top-level convenience rule that descends into test/ to
# build and run the bench binaries (see test/Makefile.am and
# test/PERFORMANCE.md). NOT wired into `make check`; release-mode
# only.
bench:
$(MAKE) -C test bench

.PHONY: bench

MOSTLYCLEANFILES = $(DX_CLEANFILES) *.gcda *.gcno *.gcov
DISTCLEANFILES = DIST_REVISION

clean-local:
rm -rf $(CHECK_HYGIENE_STAGE) $(abs_top_builddir)/.shared-check-stage $(CHECK_INSTALL_STAGE)

pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libhttpserver.pc

Expand Down
9 changes: 5 additions & 4 deletions README.CentOS-7
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
## Cent OS 7 / RHEL 7

CentOS 7 has a lower version of gcc (4.8.7) that is barely C++11 capable and this library
needs a better compiler. We recommend at least gcc 5+
CentOS 7's stock gcc (4.8.7) is far too old: this library requires a C++20 compiler
(gcc >= 10 or clang >= 13).

We recommend installing devtoolset-8
https://www.softwarecollections.org/en/scls/rhscl/devtoolset-8/
Install gcc-toolset-14 (or newer) from the RHEL/CentOS Software Collections and
`source /opt/rh/gcc-toolset-14/enable` before configuring. The same workaround applies
to RHEL 9 systems whose stock gcc-11 lacks some C++20 library features.
Loading
Loading