You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
TASK-013: remove v1 *_response subclasses, seal http_response
Deletes the eight public *_response subclasses (string/file/iovec/pipe/
deferred/empty/basic_auth_fail/digest_auth_fail) and the dispatch virtuals
(get_raw_response/decorate_response/enqueue_response) from http_response,
making the new factory-based surface (TASK-009..012) the only way to
build a response.
Phase 1 — migrate every consumer to the v2 surface:
* webserver.cpp/http_resource.cpp internal callers switched off
string_response to http_response::string()/empty().
* test/unit + test/integ + examples/* migrated to factories +
with_status()/with_header() chains.
* test/unit/iovec_response_test.cpp deleted (covered by
http_response_factories_test).
Phase 2 — delete the v1 surface:
* Eight v1 hpp + cpp pairs deleted.
* src/Makefile.am drops the deleted sources/headers and the
HAVE_BAUTH conditional.
* <httpserver.hpp> umbrella drops the eight removed includes.
* http_response gains `final`; destructor de-virtualised; the legacy
2-arg constructor (security-reviewer #24 from TASK-012) and the
get_response_code() shim are gone; struct MHD_Connection/MHD_Response
forward declarations dropped from the public header.
* webserver gains static dispatch helpers materialize_response() and
decorate_mhd_response(); friended into http_response so it can read
body_ without widening the public API.
* file() factory now defaults Content-Type to application/octet-stream
(matching v1 file_response).
* empty_render returns a default-constructed http_response so the
status_code = -1 sentinel keeps routing to internal_error_page (the
default_render_method test pins this).
* finalize_answer's catch blocks now wrap internal_error_page() with
an inner try/catch that falls back to force_our=true so a throwing
user-supplied internal_error_resource can never escape into MHD.
Acceptance:
* grep 'class \w+_response :' src/httpserver/*.hpp returns no public
subclass declarations.
* grep 'get_raw_response|decorate_response|enqueue_response'
src/httpserver/*.hpp returns only doxygen prose.
* static_assert(std::is_final_v<http_response>) compiles
(test/unit/http_response_sbo_test.cpp).
* make check: 25 PASS / 1 XFAIL (header_hygiene, expected pre-M5).
Behaviour change accepted per plan §2 / §10 and PRD §3.5: v1's
basic_auth_fail and digest_auth_fail bound to MHD's nonce/opaque
state machine via MHD_queue_basic/auth_required_response3; v2's
unauthorized() emits a static WWW-Authenticate challenge and
enqueues via MHD_queue_response. Four digest-auth round-trip tests
in test/integ/authentication.cpp updated to assert the v2 contract
(challenge issued, handshake does not complete, body remains FAIL).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
return std::make_shared<httpserver::http_response>(httpserver::http_response::string("Certificate not verified by trusted CA").with_status(httpserver::http::http_utils::http_forbidden));
return std::make_shared<httpserver::http_response>(httpserver::http_response::string("Certificate not in allowlist").with_status(httpserver::http::http_utils::http_forbidden));
97
91
}
98
92
99
93
// Check certificate validity times
@@ -102,15 +96,11 @@ class secure_resource : public httpserver::http_resource {
return std::make_shared<httpserver::http_response>(httpserver::http_response::string("Certificate not yet valid").with_status(httpserver::http::http_utils::http_forbidden));
return std::make_shared<httpserver::http_response>(httpserver::http_response::string("Certificate has expired").with_status(httpserver::http::http_utils::http_forbidden));
114
104
}
115
105
116
106
// Build response with certificate info
@@ -121,7 +111,7 @@ class secure_resource : public httpserver::http_resource {
0 commit comments