Which capabilities compile in, how they're detected, and what happens when they're absent. Build & packaging spec:
specs/architecture/08-build-and-packaging.md.
The public symbol surface is identical on every build. Every feature-gated method is always declared and linkable — only the method body branches on the build macro, either returning a documented sentinel or throwing feature_unavailable. The four HAVE_* macros are pushed via compiler -D flags (not a config.h), so no consumer include is required.
flowchart LR
subgraph det["Build detection · configure.ac"]
G["gnutls/gnutls.h"] --> HG["HAVE_GNUTLS"]
B["MHD_basic_auth_get_username_password3"] --> HB["HAVE_BAUTH"]
D["MHD_digest_auth_check3"] --> HD["HAVE_DAUTH"]
W["microhttpd_ws.h + MHD_websocket_stream_init"] --> HW["HAVE_WEBSOCKET"]
end
HG --> TLS["TLS · client certs · SNI · PSK"]
HB --> BA["Basic auth"]
HD --> DA["Digest auth"]
HW --> WS["WebSocket"]
| Feature | Detected by (configure.ac) |
Gated symbols | features() bool |
When absent |
|---|---|---|---|---|
| TLS / HTTPS | AC_CHECK_HEADER(gnutls/gnutls.h) → HAVE_GNUTLS |
http_request_impl_tls.cpp (get_tls_session, populate_all_cert_fields), http_request cert accessors, sni_credentials_cache, sni_cert_callback_func, psk_cred_handler_func, GnuTLS MHD options |
tls |
use_ssl(true) → ctor throws feature_unavailable("tls","HAVE_GNUTLS"); cert accessors return false/empty/-1; cred_type/PSK/SNI options silently dropped |
| Basic auth | AC_CHECK_LIB(microhttpd, MHD_basic_auth_get_username_password3) → HAVE_BAUTH |
fetch_user_pass, get_user/get_pass bodies |
basic_auth |
basic_auth(true) → ctor throws ("basic_auth","HAVE_BAUTH"); get_user/get_pass → empty |
| Digest auth | AC_CHECK_LIB(microhttpd, MHD_digest_auth_check3) → HAVE_DAUTH |
digest_opaque_, check_digest_auth, check_digest_auth_digest, get_digested_user, unauthorized(digest_challenge), digest_challenge_response_body, digest MHD options |
digest_auth |
digest_auth(true) → ctor throws ("digest_auth","HAVE_DAUTH"); unauthorized(digest_challenge) → throws same; check_* → WRONG_HEADER; get_digested_user → empty |
| WebSocket | AC_CHECK_HEADER(microhttpd_ws.h) + AC_CHECK_LIB(microhttpd_ws, MHD_websocket_stream_init) → HAVE_WEBSOCKET (adds -lmicrohttpd_ws) |
websocket_upgrader, real websocket_session, websocket_handler hooks, populated ws_registry, register_ws_resource/unregister_ws_resource, MHD_ALLOW_UPGRADE |
websocket |
register_ws_resource/unregister_ws_resource throw ("websocket","HAVE_WEBSOCKET"); session send/close throw same; handler hooks no-op |
Each macro is injected into AM_CXXFLAGS/AM_CFLAGS as -D<MACRO> (with a matching AM_CONDITIONAL); none is written to config.h.
| Macro | Detection | Gates |
|---|---|---|
MHD_OPTION_HTTPS_CERT_CALLBACK |
MHD-provided | SNI callback wiring (additionally requires HAVE_GNUTLS) |
MHD_VERSION |
MHD header | http_utils.cpp compat shim for pre-0.9.74 status-code spellings |
HAVE_EXPLICIT_BZERO |
AC_CHECK_DECLS([explicit_bzero]) |
secure_zero.hpp implementation (internal) |
USE_FASTOPEN |
kernel TCP_FASTOPEN probe (--enable-fastopen) |
MHD_USE_TCP_FASTOPEN daemon flag |
Minimum libmicrohttpd: 1.0.0 — configure.ac hard-errors below MHD_VERSION 0x01000000.
webserver::features()(noexcept) returns{basic_auth, digest_auth, tls, websocket}, each aconstexprresolved purely from the build macros. It reflects the library's build flags, not the caller's — the body lives inwebserver.cppprecisely so consumers see the shipped library's capabilities. It does not query MHD.http::http_utils::is_feature_supported(int)is the only runtime MHD query — wrapsMHD_is_feature_supported((enum MHD_FEATURE)…); independent of the fourHAVE_*macros.http::http_utils::get_mhd_version()returns MHD's version string.
class feature_unavailable : public std::runtime_error (always compiled). what() = "feature '<feature>' unavailable: built without <build_flag>".
webserver::webserverctor — validated lazily at construction (never at the setter):use_sslw/o GnuTLS,basic_authw/o BAuth,digest_authw/o DAuth.http_response::unauthorized(digest_challenge)w/oHAVE_DAUTH.webserver::register_ws_resource/unregister_ws_resourceand everywebsocket_sessionsend/close w/oHAVE_WEBSOCKET.
Setters never throw — they only mutate config; validation is deferred. So use_ssl(true) on a GnuTLS-off build compiles and returns fine, then throws when you construct the webserver.
| Setter | Feature | If feature absent |
|---|---|---|
use_ssl(bool) |
HAVE_GNUTLS | ctor throws |
https_mem_key/cert/trust (+ raw_*), https_mem_dhparams, https_key_password, https_priorities[_append] |
HAVE_GNUTLS (via use_ssl) |
wired only under use_ssl; otherwise inert |
cred_type(cred_type_T) |
HAVE_GNUTLS | option added only under HAVE_GNUTLS; else ignored (ctor throws first if use_ssl also set) |
psk_cred_handler(cb) |
HAVE_GNUTLS + use_ssl |
ignored otherwise |
sni_callback(cb) |
HAVE_GNUTLS + cert-callback + use_ssl |
ignored otherwise |
digest_auth_random(str), nonce_nc_size |
HAVE_DAUTH | option added only under HAVE_DAUTH; else ignored |
basic_auth(bool) |
HAVE_BAUTH | ctor throws if enabled |
digest_auth(bool) |
HAVE_DAUTH | ctor throws if enabled |
basic_auth/digest_auth default to true only when their macro is defined, so an auth-off build defaults the flag off and never throws spuriously.
- Autotools is the only build with capability detection:
configure.ac+src/Makefile.am. All fourHAVE_*and the switches above are probed here. - CMake support is consumer-side only:
cmakemodule/FindLibHttpServer.cmakeis a plain find-module (locates headers + library); it does no capability detection and does not build the library. There is no top-levelCMakeLists.txt.
See also: errors (feature_unavailable's reach — caller vs client) · class map (the gated collaborators, marked HAVE_WEBSOCKET).