Skip to content

Commit 1b830af

Browse files
committed
Migrate to libmicrohttpd 1.0.0 API with new features
Raise minimum libmicrohttpd requirement to 1.0.0 and migrate all deprecated APIs to their v3 replacements: - Basic Auth: MHD_basic_auth_get_username_password3, MHD_queue_basic_auth_required_response3 with UTF-8 support - Digest Auth: MHD_digest_auth_check3, MHD_digest_auth_check_digest3, MHD_queue_auth_required_response3 with SHA-512/256, userhash, nonce binding, and structured digest_auth_result enum Add new response types: empty_response, pipe_response, iovec_response. Add external event loop integration (run, run_wait, get_fdset, get_timeout, add_connection), daemon management (quiesce, get_listen_fd, get_active_connections, get_bound_port), and numerous new daemon options (listen_backlog, address_reuse, tcp_fastopen_queue_size, turbo, etc.). Add conditional WebSocket support via libmicrohttpd_ws. Add utility functions: reason_phrase, is_feature_supported, get_mhd_version.
1 parent 68bff78 commit 1b830af

30 files changed

Lines changed: 1402 additions & 128 deletions

ChangeLog

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,27 @@
11
Version 0.20.0
22

3+
Raised minimum libmicrohttpd requirement to 1.0.0.
4+
Migrated Basic Auth to v3 API (MHD_basic_auth_get_username_password3,
5+
MHD_queue_basic_auth_required_response3) with UTF-8 support.
6+
Migrated Digest Auth to v3 API (MHD_digest_auth_check3,
7+
MHD_digest_auth_check_digest3, MHD_queue_auth_required_response3)
8+
with SHA-512/256 support, userhash, nonce binding, and structured
9+
digest_auth_result enum. Default algorithm changed to SHA-256.
10+
Added new response types: empty_response, pipe_response, iovec_response.
11+
Added external event loop integration: webserver::run(), run_wait(),
12+
get_fdset(), get_timeout(), add_connection().
13+
Added daemon management: quiesce(), get_listen_fd(),
14+
get_active_connections(), get_bound_port().
15+
Added daemon options: listen_backlog, address_reuse,
16+
connection_memory_increment, tcp_fastopen_queue_size,
17+
sigpipe_handled_by_app, https_mem_dhparams, https_key_password,
18+
https_priorities_append, no_alpn, client_discipline_level.
19+
Added startup flags: no_listen_socket, no_thread_safety, turbo,
20+
suppress_date_header.
21+
Added WebSocket support (conditional on HAVE_WEBSOCKET):
22+
websocket_handler, websocket_session, register_ws_resource().
23+
Added utility functions: reason_phrase(), is_feature_supported(),
24+
get_mhd_version().
325
Added conditional compilation for basic auth (HAVE_BAUTH), mirroring
426
existing HAVE_DAUTH pattern for digest auth. Basic auth support
527
is auto-detected via AC_CHECK_LIB and can be disabled at build time.

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ libhttpserver can be used without any dependencies aside from libmicrohttpd.
8080
The minimum versions required are:
8181
* g++ >= 5.5.0 or clang-3.6
8282
* C++17 or newer
83-
* libmicrohttpd >= 0.9.64
83+
* libmicrohttpd >= 1.0.0
8484
* [Optionally]: for TLS (HTTPS) support, you'll need [libgnutls](http://www.gnutls.org/).
8585
* [Optionally]: to compile the code-reference, you'll need [doxygen](http://www.doxygen.nl/).
8686

@@ -141,7 +141,7 @@ MSYS2 provides multiple shell environments with different purposes. Understandin
141141
pacman -S --needed mingw-w64-x86_64-{gcc,libtool,make,pkg-config,doxygen,gnutls,curl} autotools
142142
```
143143

144-
4. Build and install [libmicrohttpd](https://www.gnu.org/software/libmicrohttpd/) (>= 0.9.64)
144+
4. Build and install [libmicrohttpd](https://www.gnu.org/software/libmicrohttpd/) (>= 1.0.0)
145145

146146
5. Build libhttpserver:
147147
```bash
@@ -389,7 +389,7 @@ You can also check this example on [github](https://github.com/etr/libhttpserver
389389
* _.https_mem_trust(**const std::string&** filename):_ String representing the path to a file containing the CA certificate to be used by the HTTPS daemon to authenticate and trust clients certificates. The presence of this option activates the request of certificate to the client. The request to the client is marked optional, and it is the responsibility of the server to check the presence of the certificate if needed. Note that most browsers will only present a client certificate only if they have one matching the specified CA, not sending any certificate otherwise.
390390
* _.https_priorities(**const std::string&** priority_string):_ SSL/TLS protocol version and ciphers. Must be followed by a string specifying the SSL/TLS protocol versions and ciphers that are acceptable for the application. The string is passed unchanged to gnutls_priority_init. If this option is not specified, `"NORMAL"` is used.
391391
* _.psk_cred_handler(**psk_cred_handler_callback** handler):_ Sets a callback function for TLS-PSK (Pre-Shared Key) authentication. The callback receives a username and should return the corresponding hex-encoded PSK, or an empty string if the user is unknown. This option requires `use_ssl()`, `cred_type(http::http_utils::PSK)`, and an appropriate `https_priorities()` string that enables PSK cipher suites. PSK authentication allows TLS without certificates by using a shared secret key.
392-
* _.sni_callback(**sni_callback_t** callback):_ Sets a callback function for SNI (Server Name Indication) support. The callback receives the server name requested by the client and should return a `std::pair<std::string, std::string>` containing the PEM-encoded certificate and key for that server name. Return empty strings to use the default certificate. Requires libmicrohttpd 0.9.71+ with GnuTLS.
392+
* _.sni_callback(**sni_callback_t** callback):_ Sets a callback function for SNI (Server Name Indication) support. The callback receives the server name requested by the client and should return a `std::pair<std::string, std::string>` containing the PEM-encoded certificate and key for that server name. Return empty strings to use the default certificate. Requires libmicrohttpd 1.0.0+ with GnuTLS.
393393

394394
#### Minimal example using HTTPS
395395
```cpp
@@ -1190,7 +1190,7 @@ To use SNI with libhttpserver, configure an SNI callback that returns the certif
11901190
}
11911191
```
11921192
1193-
Note: SNI support requires libmicrohttpd 0.9.71 or later compiled with GnuTLS.
1193+
Note: SNI support requires libmicrohttpd 1.0.0 or later compiled with GnuTLS.
11941194
11951195
[Back to TOC](#table-of-contents)
11961196

configure.ac

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -108,18 +108,18 @@ AC_CHECK_HEADER([gnutls/gnutls.h],[have_gnutls="yes"],[AC_MSG_WARN("gnutls/gnutl
108108
# Checks for libmicrohttpd
109109
if test x"$host" = x"$build"; then
110110
AC_CHECK_HEADER([microhttpd.h],
111-
AC_CHECK_LIB([microhttpd], [MHD_get_fdset2],
112-
[AC_MSG_CHECKING([for libmicrohttpd >= 0.9.64])
111+
AC_CHECK_LIB([microhttpd], [MHD_start_daemon],
112+
[AC_MSG_CHECKING([for libmicrohttpd >= 1.0.0])
113113
AC_COMPILE_IFELSE(
114114
[AC_LANG_SOURCE([
115115
#include <microhttpd.h>
116-
#if (MHD_VERSION < 0x00096400)
117-
#error needs at least version 0.9.64
116+
#if (MHD_VERSION < 0x01000000)
117+
#error needs at least version 1.0.0
118118
#endif
119119
int main () { return 0; }
120120
])],
121121
[],
122-
[AC_MSG_ERROR("libmicrohttpd is too old - install libmicrohttpd >= 0.9.64")]
122+
[AC_MSG_ERROR("libmicrohttpd is too old - install libmicrohttpd >= 1.0.0")]
123123
)
124124
],
125125
[AC_MSG_ERROR(["libmicrohttpd not found"])]
@@ -133,7 +133,7 @@ if test x"$host" = x"$build"; then
133133
cond_cross_compile="no"
134134
else
135135
AC_CHECK_HEADER([microhttpd.h],
136-
AC_CHECK_LIB([microhttpd], [MHD_get_fdset2],
136+
AC_CHECK_LIB([microhttpd], [MHD_start_daemon],
137137
[],
138138
[AC_MSG_ERROR(["libmicrohttpd not found"])]
139139
),
@@ -149,15 +149,22 @@ fi
149149
AM_CONDITIONAL([COND_CROSS_COMPILE],[test x"$cond_cross_compile" = x"yes"])
150150
AC_SUBST(COND_CROSS_COMPILE)
151151

152-
# Check for basic auth support in libmicrohttpd
153-
AC_CHECK_LIB([microhttpd], [MHD_queue_basic_auth_fail_response],
152+
# Check for basic auth v3 support in libmicrohttpd
153+
AC_CHECK_LIB([microhttpd], [MHD_basic_auth_get_username_password3],
154154
[have_bauth="yes"],
155-
[have_bauth="no"; AC_MSG_WARN("libmicrohttpd basic auth support not found. Basic auth will be disabled")])
155+
[have_bauth="no"; AC_MSG_WARN("libmicrohttpd basic auth v3 support not found. Basic auth will be disabled")])
156156

157-
# Check for digest auth support in libmicrohttpd
158-
AC_CHECK_LIB([microhttpd], [MHD_queue_auth_fail_response],
157+
# Check for digest auth v3 support in libmicrohttpd
158+
AC_CHECK_LIB([microhttpd], [MHD_digest_auth_check3],
159159
[have_dauth="yes"],
160-
[have_dauth="no"; AC_MSG_WARN("libmicrohttpd digest auth support not found. Digest auth will be disabled")])
160+
[have_dauth="no"; AC_MSG_WARN("libmicrohttpd digest auth v3 support not found. Digest auth will be disabled")])
161+
162+
# Check for WebSocket support in libmicrohttpd_ws
163+
AC_CHECK_HEADER([microhttpd_ws.h],
164+
[AC_CHECK_LIB([microhttpd_ws], [MHD_websocket_stream_init],
165+
[have_websocket="yes"],
166+
[have_websocket="no"; AC_MSG_WARN("libmicrohttpd_ws not found. WebSocket support will be disabled")])],
167+
[have_websocket="no"; AC_MSG_WARN("microhttpd_ws.h not found. WebSocket support will be disabled")])
161168

162169
AC_MSG_CHECKING([whether to build with TCP_FASTOPEN support])
163170
AC_ARG_ENABLE([fastopen],
@@ -283,6 +290,14 @@ fi
283290

284291
AM_CONDITIONAL([HAVE_DAUTH],[test x"$have_dauth" = x"yes"])
285292

293+
if test x"$have_websocket" = x"yes"; then
294+
AM_CXXFLAGS="$AM_CXXFLAGS -DHAVE_WEBSOCKET"
295+
AM_CFLAGS="$AM_CXXFLAGS -DHAVE_WEBSOCKET"
296+
LHT_LIBDEPS="$LHT_LIBDEPS -lmicrohttpd_ws"
297+
fi
298+
299+
AM_CONDITIONAL([HAVE_WEBSOCKET],[test x"$have_websocket" = x"yes"])
300+
286301
DX_HTML_FEATURE(ON)
287302
DX_CHM_FEATURE(OFF)
288303
DX_CHI_FEATURE(OFF)
@@ -341,6 +356,7 @@ AC_MSG_NOTICE([Configuration Summary:
341356
TLS Enabled : ${have_gnutls}
342357
Basic Auth : ${have_bauth}
343358
Digest Auth : ${have_dauth}
359+
WebSocket : ${have_websocket}
344360
TCP_FASTOPEN : ${is_fastopen_supported}
345361
Static : ${static}
346362
Windows build : ${is_windows}

examples/digest_authentication.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,21 @@
2727
class digest_resource : public httpserver::http_resource {
2828
public:
2929
std::shared_ptr<httpserver::http_response> render_GET(const httpserver::http_request& req) {
30+
using httpserver::http::http_utils;
3031
if (req.get_digested_user() == "") {
31-
return std::shared_ptr<httpserver::digest_auth_fail_response>(new httpserver::digest_auth_fail_response("FAIL", "test@example.com", MY_OPAQUE, true));
32+
return std::make_shared<httpserver::digest_auth_fail_response>("FAIL", "test@example.com", MY_OPAQUE, true,
33+
http_utils::http_ok, http_utils::text_plain, http_utils::digest_algorithm::MD5);
3234
} else {
33-
bool reload_nonce = false;
34-
if (!req.check_digest_auth("test@example.com", "mypass", 300, &reload_nonce)) {
35-
return std::shared_ptr<httpserver::digest_auth_fail_response>(new httpserver::digest_auth_fail_response("FAIL", "test@example.com", MY_OPAQUE, reload_nonce));
35+
auto result = req.check_digest_auth("test@example.com", "mypass", 300, 0, http_utils::digest_algorithm::MD5);
36+
if (result == http_utils::digest_auth_result::NONCE_STALE) {
37+
return std::make_shared<httpserver::digest_auth_fail_response>("FAIL", "test@example.com", MY_OPAQUE, true,
38+
http_utils::http_ok, http_utils::text_plain, http_utils::digest_algorithm::MD5);
39+
} else if (result != http_utils::digest_auth_result::OK) {
40+
return std::make_shared<httpserver::digest_auth_fail_response>("FAIL", "test@example.com", MY_OPAQUE, false,
41+
http_utils::http_ok, http_utils::text_plain, http_utils::digest_algorithm::MD5);
3642
}
3743
}
38-
return std::shared_ptr<httpserver::string_response>(new httpserver::string_response("SUCCESS", 200, "text/plain"));
44+
return std::make_shared<httpserver::string_response>("SUCCESS", 200, "text/plain");
3945
}
4046
};
4147

libhttpserver.pc.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ includedir=@includedir@
66
Name: libhttpserver
77
Description: A C++ library for creating an embedded Rest HTTP server
88
Version: @VERSION@
9-
Requires: libmicrohttpd >= 0.9.52
9+
Requires: libmicrohttpd >= 1.0.0
1010
Conflicts:
1111
Libs: -L${libdir} -lhttpserver
1212
Libs.private: @LHT_LIBDEPS@

src/Makefile.am

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,20 @@
1919
AM_CPPFLAGS = -I../ -I$(srcdir)/httpserver/
2020
METASOURCES = AUTO
2121
lib_LTLIBRARIES = libhttpserver.la
22-
libhttpserver_la_SOURCES = string_utilities.cpp webserver.cpp http_utils.cpp file_info.cpp http_request.cpp http_response.cpp string_response.cpp digest_auth_fail_response.cpp deferred_response.cpp file_response.cpp http_resource.cpp create_webserver.cpp details/http_endpoint.cpp
22+
libhttpserver_la_SOURCES = string_utilities.cpp webserver.cpp http_utils.cpp file_info.cpp http_request.cpp http_response.cpp string_response.cpp digest_auth_fail_response.cpp deferred_response.cpp file_response.cpp pipe_response.cpp empty_response.cpp iovec_response.cpp http_resource.cpp create_webserver.cpp details/http_endpoint.cpp
2323
noinst_HEADERS = httpserver/string_utilities.hpp httpserver/details/modded_request.hpp gettext.h
24-
nobase_include_HEADERS = httpserver.hpp httpserver/create_webserver.hpp httpserver/webserver.hpp httpserver/http_utils.hpp httpserver/file_info.hpp httpserver/details/http_endpoint.hpp httpserver/http_request.hpp httpserver/http_response.hpp httpserver/http_resource.hpp httpserver/string_response.hpp httpserver/digest_auth_fail_response.hpp httpserver/deferred_response.hpp httpserver/file_response.hpp httpserver/http_arg_value.hpp
24+
nobase_include_HEADERS = httpserver.hpp httpserver/create_webserver.hpp httpserver/webserver.hpp httpserver/http_utils.hpp httpserver/file_info.hpp httpserver/details/http_endpoint.hpp httpserver/http_request.hpp httpserver/http_response.hpp httpserver/http_resource.hpp httpserver/string_response.hpp httpserver/digest_auth_fail_response.hpp httpserver/deferred_response.hpp httpserver/file_response.hpp httpserver/pipe_response.hpp httpserver/empty_response.hpp httpserver/iovec_response.hpp httpserver/http_arg_value.hpp
2525

2626
if HAVE_BAUTH
2727
libhttpserver_la_SOURCES += basic_auth_fail_response.cpp
2828
nobase_include_HEADERS += httpserver/basic_auth_fail_response.hpp
2929
endif
3030

31+
if HAVE_WEBSOCKET
32+
libhttpserver_la_SOURCES += websocket_handler.cpp
33+
nobase_include_HEADERS += httpserver/websocket_handler.hpp
34+
endif
35+
3136
AM_CXXFLAGS += -fPIC -Wall
3237

3338
if COND_GCOV
@@ -38,6 +43,9 @@ endif
3843

3944
if !COND_CROSS_COMPILE
4045
libhttpserver_la_LIBADD = -lmicrohttpd
46+
if HAVE_WEBSOCKET
47+
libhttpserver_la_LIBADD += -lmicrohttpd_ws
48+
endif
4149
endif
4250

4351
libhttpserver_la_CFLAGS = $(AM_CFLAGS)

src/basic_auth_fail_response.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ struct MHD_Response;
3030
namespace httpserver {
3131

3232
int basic_auth_fail_response::enqueue_response(MHD_Connection* connection, MHD_Response* response) {
33-
return MHD_queue_basic_auth_fail_response(connection, realm.c_str(), response);
33+
return MHD_queue_basic_auth_required_response3(connection, realm.c_str(), prefer_utf8 ? MHD_YES : MHD_NO, response);
3434
}
3535

3636
} // namespace httpserver

src/digest_auth_fail_response.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,17 @@ struct MHD_Response;
3030
namespace httpserver {
3131

3232
int digest_auth_fail_response::enqueue_response(MHD_Connection* connection, MHD_Response* response) {
33-
return MHD_queue_auth_fail_response2(
33+
return MHD_queue_auth_required_response3(
3434
connection,
3535
realm.c_str(),
3636
opaque.c_str(),
37+
domain.empty() ? nullptr : domain.c_str(),
3738
response,
38-
reload_nonce ? MHD_YES : MHD_NO,
39-
static_cast<MHD_DigestAuthAlgorithm>(algorithm));
39+
signal_stale ? MHD_YES : MHD_NO,
40+
MHD_DIGEST_AUTH_MULT_QOP_ANY_NON_INT,
41+
static_cast<MHD_DigestAuthMultiAlgo3>(algorithm),
42+
userhash_support ? MHD_YES : MHD_NO,
43+
prefer_utf8 ? MHD_YES : MHD_NO);
4044
}
4145

4246
} // namespace httpserver

src/empty_response.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
This file is part of libhttpserver
3+
Copyright (C) 2011-2019 Sebastiano Merlino
4+
5+
This library is free software; you can redistribute it and/or
6+
modify it under the terms of the GNU Lesser General Public
7+
License as published by the Free Software Foundation; either
8+
version 2.1 of the License, or (at your option) any later version.
9+
10+
This library is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public
16+
License along with this library; if not, write to the Free Software
17+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
18+
USA
19+
*/
20+
21+
#include "httpserver/empty_response.hpp"
22+
#include <microhttpd.h>
23+
24+
struct MHD_Response;
25+
26+
namespace httpserver {
27+
28+
MHD_Response* empty_response::get_raw_response() {
29+
return MHD_create_response_empty(static_cast<MHD_ResponseFlags>(flags));
30+
}
31+
32+
} // namespace httpserver

0 commit comments

Comments
 (0)