Skip to content

Commit 3d5474e

Browse files
etrclaude
andcommitted
refactor: extract auth surface from http_request.hpp (656 → 497)
Step 2 of the FILE_LOC_MAX ratchet. Moves the auth/credentials member declarations of class http_request — basic auth getters (get_user, get_pass, get_digested_user), the TLS / client-certificate cluster (has_tls_session, has_client_certificate, get_client_cert_*, is_client_cert_verified, get_client_cert_not_before/after), and the digest-auth verification entrypoints (check_digest_auth, check_digest_auth_digest) — into a sibling public header httpserver/http_request_auth.hpp. Mechanism: in-class-body #include. The sibling header carries declarations only and gates itself behind SRC_HTTPSERVER_HTTP_REQUEST_HPP_INSIDE_CLASS_, which is #define'd just before the include inside class http_request { ... } and #undef'd immediately after. Including the sibling in any other context raises a #error with a pointer back to http_request.hpp. Doxygen still picks up the declarations through textual inclusion, so the generated docs are unchanged. The header is installed (nobase_include_HEADERS) so consumers building against an installed libhttpserver see it transitively via <httpserver.hpp> / httpserver/http_request.hpp; it is NOT added to the umbrella's sub-header list because the inner gate forbids standalone inclusion. No public ABI change: the methods remain member functions of http_request, declared in the same access section, same signatures, same noexcept. Consumer code (test/, examples/) is untouched. FILE_LOC_MAX stays at 2700 — webserver.cpp (2673) still pins it. Offender list down to five files. Verification: make check 51/51 PASS (includes hygiene, install-layout, doxygen, examples, readme, release-notes) ./scripts/check-file-size.sh PASS at FILE_LOC_MAX=2700 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 3ab0963 commit 3d5474e

4 files changed

Lines changed: 235 additions & 168 deletions

File tree

scripts/check-file-size.sh

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
# src/httpserver/webserver.hpp 845
3636
# src/http_utils.cpp 730
3737
# src/httpserver/detail/webserver_impl.hpp 674
38-
# src/httpserver/http_request.hpp 656
3938
#
4039
# FILE_LOC_MAX is pinned by the largest unfixed file (webserver.cpp at
4140
# 2673), so it cannot drop until the top offender is decomposed. The

src/Makefile.am

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ libhttpserver_la_SOURCES = string_utilities.cpp webserver.cpp http_utils.cpp fil
3030
# Detail headers (httpserver/detail/*.hpp) live here so they cannot leak to
3131
# downstream consumers — the public surface comes in through <httpserver.hpp>.
3232
noinst_HEADERS = httpserver/string_utilities.hpp httpserver/detail/modded_request.hpp httpserver/detail/http_endpoint.hpp httpserver/detail/body.hpp httpserver/detail/webserver_impl.hpp httpserver/detail/http_request_impl.hpp httpserver/detail/route_entry.hpp httpserver/detail/lambda_resource.hpp httpserver/detail/radix_tree.hpp httpserver/detail/route_cache.hpp gettext.h
33-
nobase_include_HEADERS = httpserver.hpp httpserver/body_kind.hpp httpserver/constants.hpp httpserver/create_webserver.hpp httpserver/create_test_request.hpp httpserver/webserver.hpp httpserver/websocket_handler.hpp httpserver/http_utils.hpp httpserver/ip_representation.hpp httpserver/file_info.hpp httpserver/http_request.hpp httpserver/http_response.hpp httpserver/http_resource.hpp httpserver/feature_unavailable.hpp httpserver/iovec_entry.hpp httpserver/http_arg_value.hpp httpserver/http_method.hpp httpserver/hook_phase.hpp httpserver/hook_action.hpp httpserver/hook_handle.hpp httpserver/hook_context.hpp
33+
nobase_include_HEADERS = httpserver.hpp httpserver/body_kind.hpp httpserver/constants.hpp httpserver/create_webserver.hpp httpserver/create_test_request.hpp httpserver/webserver.hpp httpserver/websocket_handler.hpp httpserver/http_utils.hpp httpserver/ip_representation.hpp httpserver/file_info.hpp httpserver/http_request.hpp httpserver/http_request_auth.hpp httpserver/http_response.hpp httpserver/http_resource.hpp httpserver/feature_unavailable.hpp httpserver/iovec_entry.hpp httpserver/http_arg_value.hpp httpserver/http_method.hpp httpserver/hook_phase.hpp httpserver/hook_action.hpp httpserver/hook_handle.hpp httpserver/hook_context.hpp
3434

3535
AM_CXXFLAGS += -fPIC -Wall
3636

src/httpserver/http_request.hpp

Lines changed: 7 additions & 166 deletions
Original file line numberDiff line numberDiff line change
@@ -135,38 +135,13 @@ class http_request {
135135
public:
136136
static const char EMPTY[];
137137

138-
/**
139-
* Method used to get the username eventually passed through basic authentication.
140-
* @return string representation of the username.
141-
* @note The returned view is only valid within the handler's call frame.
142-
* Copy into std::string if the value must outlast the handler.
143-
* @note (TASK-034 / PRD-FLG-REQ-001) Declared unconditionally.
144-
* When HAVE_BAUTH is undefined the implementation returns an
145-
* empty std::string_view sentinel (architecture spec §7).
146-
**/
147-
std::string_view get_user() const;
148-
149-
/**
150-
* Method used to get the username extracted from a digest authentication.
151-
* @return the username.
152-
* @note The returned view is only valid within the handler's call frame.
153-
* Copy into std::string if the value must outlast the handler.
154-
* @note (TASK-034 / PRD-FLG-REQ-001) Declared unconditionally.
155-
* When HAVE_DAUTH is undefined the implementation returns an
156-
* empty std::string_view sentinel (architecture spec §7).
157-
**/
158-
std::string_view get_digested_user() const;
159-
160-
/**
161-
* Method used to get the password eventually passed through basic authentication.
162-
* @return string representation of the password.
163-
* @note The returned view is only valid within the handler's call frame.
164-
* Copy into std::string if the value must outlast the handler.
165-
* @note (TASK-034 / PRD-FLG-REQ-001) Declared unconditionally.
166-
* When HAVE_BAUTH is undefined the implementation returns an
167-
* empty std::string_view sentinel (architecture spec §7).
168-
**/
169-
std::string_view get_pass() const;
138+
// Basic auth, TLS/client-cert, and digest-auth member declarations
139+
// live in a sibling header to keep this class definition under the
140+
// project per-file LOC ceiling. The inner gate forces the header
141+
// to be included only from within this class body.
142+
#define SRC_HTTPSERVER_HTTP_REQUEST_HPP_INSIDE_CLASS_
143+
#include "httpserver/http_request_auth.hpp"
144+
#undef SRC_HTTPSERVER_HTTP_REQUEST_HPP_INSIDE_CLASS_
170145

171146
/**
172147
* Method used to get the path requested.
@@ -344,94 +319,6 @@ class http_request {
344319
return version;
345320
}
346321

347-
// ---------------------------------------------------------------
348-
// TASK-019: high-level GnuTLS accessors. Declared unconditionally
349-
// (no build-flag preprocessor gate) so the public surface is
350-
// identical in TLS-enabled and TLS-disabled builds. When the
351-
// library is built without GnuTLS the implementations return
352-
// empty / false / -1 sentinels without throwing (architecture
353-
// spec §7).
354-
// ---------------------------------------------------------------
355-
356-
/**
357-
* Method used to check whether the request was carried over a TLS
358-
* session.
359-
* @return true when a live TLS session is present, false otherwise
360-
* (including when HAVE_GNUTLS is disabled at build time).
361-
**/
362-
bool has_tls_session() const noexcept;
363-
364-
/**
365-
* Method used to check whether the peer presented a client
366-
* certificate over the TLS session.
367-
* @return true when a peer certificate is available, false
368-
* otherwise (including when HAVE_GNUTLS is disabled at
369-
* build time).
370-
**/
371-
bool has_client_certificate() const noexcept;
372-
373-
/**
374-
* Subject Distinguished Name from the client certificate.
375-
* @return string_view over the cached subject DN; empty when no
376-
* peer cert is present or HAVE_GNUTLS is disabled.
377-
* @note The returned view aliases storage owned by this
378-
* http_request and is only valid for the lifetime of the
379-
* request object (typically the handler invocation). Copy
380-
* into std::string to extend the lifetime.
381-
**/
382-
std::string_view get_client_cert_dn() const;
383-
384-
/**
385-
* Issuer Distinguished Name from the client certificate.
386-
* @return string_view over the cached issuer DN; empty when no
387-
* peer cert is present or HAVE_GNUTLS is disabled.
388-
* @note Same lifetime contract as get_client_cert_dn().
389-
**/
390-
std::string_view get_client_cert_issuer_dn() const;
391-
392-
/**
393-
* Common Name (CN) from the client certificate subject.
394-
* @return string_view over the cached CN; empty when no peer cert
395-
* is present, the cert subject has no CN attribute, or
396-
* HAVE_GNUTLS is disabled.
397-
* @note Multi-CN subjects: only the first CN is reported.
398-
* @note Same lifetime contract as get_client_cert_dn().
399-
**/
400-
std::string_view get_client_cert_cn() const;
401-
402-
/**
403-
* SHA-256 fingerprint of the client certificate (hex-encoded).
404-
* @return string_view over the lowercase hex-encoded SHA-256
405-
* fingerprint (64 hex chars); empty when no peer cert is
406-
* present or HAVE_GNUTLS is disabled.
407-
* @note Same lifetime contract as get_client_cert_dn().
408-
**/
409-
std::string_view get_client_cert_fingerprint_sha256() const;
410-
411-
/**
412-
* Whether the peer certificate chain validated successfully against
413-
* the configured trust anchors.
414-
* @return true on successful validation, false otherwise (including
415-
* when no cert was presented or HAVE_GNUTLS is disabled).
416-
**/
417-
bool is_client_cert_verified() const noexcept;
418-
419-
/**
420-
* Activation time (`Not Before`) of the client certificate, in
421-
* seconds since the UNIX epoch.
422-
* @return seconds-since-epoch as a 64-bit signed integer; -1 when
423-
* no peer cert is present or HAVE_GNUTLS is disabled.
424-
**/
425-
std::int64_t get_client_cert_not_before() const noexcept;
426-
427-
/**
428-
* Expiration time (`Not After`) of the client certificate, in
429-
* seconds since the UNIX epoch.
430-
* @return seconds-since-epoch as a 64-bit signed integer; -1 when
431-
* no peer cert is present or HAVE_GNUTLS is disabled.
432-
**/
433-
std::int64_t get_client_cert_not_after() const noexcept;
434-
435322
/**
436323
* Method used to get the requestor.
437324
* @return the requestor (IP address string).
@@ -445,52 +332,6 @@ class http_request {
445332
**/
446333
uint16_t get_requestor_port() const;
447334

448-
/**
449-
* Digest-authenticate the current request against (@p realm, @p password).
450-
*
451-
* (TASK-034 / PRD-FLG-REQ-001) Declared unconditionally. When the
452-
* library was built without HAVE_DAUTH the implementation returns
453-
* the sentinel `digest_auth_result::WRONG_HEADER` (architecture
454-
* spec §7 "returns a sentinel result") without touching MHD.
455-
*
456-
* @param realm protection realm advertised in the WWW-Authenticate header.
457-
* @param password cleartext password to verify against.
458-
* @param nonce_timeout nonce lifetime in seconds (0 = backend default).
459-
* @param max_nc max accepted nonce-count value (0 = backend default).
460-
* @param algo digest hash algorithm; defaults to SHA-256.
461-
* @return one of the @ref httpserver::http::http_utils::digest_auth_result values.
462-
**/
463-
http::http_utils::digest_auth_result check_digest_auth(
464-
const std::string& realm,
465-
const std::string& password,
466-
unsigned int nonce_timeout = 0,
467-
uint32_t max_nc = 0,
468-
http::http_utils::digest_algorithm algo = http::http_utils::digest_algorithm::SHA256) const;
469-
470-
/**
471-
* Digest-authenticate using a pre-computed user digest (no cleartext password).
472-
*
473-
* Variant of @ref check_digest_auth that takes a raw H(A1) digest
474-
* instead of a cleartext password. Same feature-flag behaviour:
475-
* declared unconditionally; returns
476-
* `digest_auth_result::WRONG_HEADER` on HAVE_DAUTH-off builds.
477-
*
478-
* @param realm protection realm advertised in the WWW-Authenticate header.
479-
* @param userdigest pre-computed digest of the username/realm/password.
480-
* @param userdigest_size size of @p userdigest in bytes.
481-
* @param nonce_timeout nonce lifetime in seconds (0 = backend default).
482-
* @param max_nc max accepted nonce-count value (0 = backend default).
483-
* @param algo digest hash algorithm; defaults to SHA-256.
484-
* @return one of the @ref httpserver::http::http_utils::digest_auth_result values.
485-
**/
486-
http::http_utils::digest_auth_result check_digest_auth_digest(
487-
const std::string& realm,
488-
const void* userdigest,
489-
size_t userdigest_size,
490-
unsigned int nonce_timeout = 0,
491-
uint32_t max_nc = 0,
492-
http::http_utils::digest_algorithm algo = http::http_utils::digest_algorithm::SHA256) const;
493-
494335
friend std::ostream &operator<< (std::ostream &os, http_request &r);
495336

496337
~http_request();

0 commit comments

Comments
 (0)