Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
22 changes: 22 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
Version 0.20.0

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.
Migrated Digest Auth to v3 API (MHD_digest_auth_check3,
MHD_digest_auth_check_digest3, MHD_queue_auth_required_response3)
with SHA-512/256 support, userhash, nonce binding, and structured
digest_auth_result enum. Default algorithm changed to SHA-256.
Added new response types: empty_response, pipe_response, iovec_response.
Added external event loop integration: webserver::run(), run_wait(),
get_fdset(), get_timeout(), add_connection().
Added daemon management: quiesce(), get_listen_fd(),
get_active_connections(), get_bound_port().
Added daemon options: listen_backlog, address_reuse,
connection_memory_increment, tcp_fastopen_queue_size,
sigpipe_handled_by_app, https_mem_dhparams, https_key_password,
https_priorities_append, no_alpn, client_discipline_level.
Added startup flags: no_listen_socket, no_thread_safety, turbo,
suppress_date_header.
Added WebSocket support (conditional on HAVE_WEBSOCKET):
websocket_handler, websocket_session, register_ws_resource().
Added utility functions: reason_phrase(), is_feature_supported(),
get_mhd_version().
Added conditional compilation for basic auth (HAVE_BAUTH), mirroring
existing HAVE_DAUTH pattern for digest auth. Basic auth support
is auto-detected via AC_CHECK_LIB and can be disabled at build time.
Expand Down
486 changes: 470 additions & 16 deletions README.md

Large diffs are not rendered by default.

40 changes: 28 additions & 12 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -108,18 +108,18 @@ AC_CHECK_HEADER([gnutls/gnutls.h],[have_gnutls="yes"],[AC_MSG_WARN("gnutls/gnutl
# Checks for libmicrohttpd
if test x"$host" = x"$build"; then
AC_CHECK_HEADER([microhttpd.h],
AC_CHECK_LIB([microhttpd], [MHD_get_fdset2],
[AC_MSG_CHECKING([for libmicrohttpd >= 0.9.64])
AC_CHECK_LIB([microhttpd], [MHD_start_daemon],
[AC_MSG_CHECKING([for libmicrohttpd >= 1.0.0])
AC_COMPILE_IFELSE(
[AC_LANG_SOURCE([
#include <microhttpd.h>
#if (MHD_VERSION < 0x00096400)
#error needs at least version 0.9.64
#if (MHD_VERSION < 0x01000000)
#error needs at least version 1.0.0
#endif
int main () { return 0; }
])],
[],
[AC_MSG_ERROR("libmicrohttpd is too old - install libmicrohttpd >= 0.9.64")]
[AC_MSG_ERROR("libmicrohttpd is too old - install libmicrohttpd >= 1.0.0")]
)
],
[AC_MSG_ERROR(["libmicrohttpd not found"])]
Expand All @@ -133,7 +133,7 @@ if test x"$host" = x"$build"; then
cond_cross_compile="no"
else
AC_CHECK_HEADER([microhttpd.h],
AC_CHECK_LIB([microhttpd], [MHD_get_fdset2],
AC_CHECK_LIB([microhttpd], [MHD_start_daemon],
[],
[AC_MSG_ERROR(["libmicrohttpd not found"])]
),
Expand All @@ -149,15 +149,22 @@ fi
AM_CONDITIONAL([COND_CROSS_COMPILE],[test x"$cond_cross_compile" = x"yes"])
AC_SUBST(COND_CROSS_COMPILE)

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

# Check for digest auth support in libmicrohttpd
AC_CHECK_LIB([microhttpd], [MHD_queue_auth_fail_response],
# Check for digest auth v3 support in libmicrohttpd
AC_CHECK_LIB([microhttpd], [MHD_digest_auth_check3],
[have_dauth="yes"],
[have_dauth="no"; AC_MSG_WARN("libmicrohttpd digest auth support not found. Digest auth will be disabled")])
[have_dauth="no"; AC_MSG_WARN("libmicrohttpd digest auth v3 support not found. Digest auth will be disabled")])

# Check for WebSocket support in libmicrohttpd_ws
AC_CHECK_HEADER([microhttpd_ws.h],
[AC_CHECK_LIB([microhttpd_ws], [MHD_websocket_stream_init],
[have_websocket="yes"],
[have_websocket="no"; AC_MSG_WARN("libmicrohttpd_ws not found. WebSocket support will be disabled")])],
[have_websocket="no"; AC_MSG_WARN("microhttpd_ws.h not found. WebSocket support will be disabled")])

AC_MSG_CHECKING([whether to build with TCP_FASTOPEN support])
AC_ARG_ENABLE([fastopen],
Expand Down Expand Up @@ -283,6 +290,14 @@ fi

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

if test x"$have_websocket" = x"yes"; then
AM_CXXFLAGS="$AM_CXXFLAGS -DHAVE_WEBSOCKET"
AM_CFLAGS="$AM_CXXFLAGS -DHAVE_WEBSOCKET"
LHT_LIBDEPS="$LHT_LIBDEPS -lmicrohttpd_ws"
fi

AM_CONDITIONAL([HAVE_WEBSOCKET],[test x"$have_websocket" = x"yes"])

DX_HTML_FEATURE(ON)
DX_CHM_FEATURE(OFF)
DX_CHI_FEATURE(OFF)
Expand Down Expand Up @@ -341,6 +356,7 @@ AC_MSG_NOTICE([Configuration Summary:
TLS Enabled : ${have_gnutls}
Basic Auth : ${have_bauth}
Digest Auth : ${have_dauth}
WebSocket : ${have_websocket}
TCP_FASTOPEN : ${is_fastopen_supported}
Static : ${static}
Windows build : ${is_windows}
Expand Down
14 changes: 13 additions & 1 deletion examples/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
LDADD = $(top_builddir)/src/libhttpserver.la
AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/src/httpserver/
METASOURCES = AUTO
noinst_PROGRAMS = hello_world service minimal_hello_world custom_error allowing_disallowing_methods handlers hello_with_get_arg args_processing setting_headers custom_access_log minimal_https minimal_file_response minimal_deferred url_registration minimal_ip_ban benchmark_select benchmark_threads benchmark_nodelay deferred_with_accumulator file_upload file_upload_with_callback
noinst_PROGRAMS = hello_world service minimal_hello_world custom_error allowing_disallowing_methods handlers hello_with_get_arg args_processing setting_headers custom_access_log minimal_https minimal_file_response minimal_deferred url_registration minimal_ip_ban benchmark_select benchmark_threads benchmark_nodelay deferred_with_accumulator file_upload file_upload_with_callback empty_response_example iovec_response_example pipe_response_example daemon_info external_event_loop turbo_mode

hello_world_SOURCES = hello_world.cpp
service_SOURCES = service.cpp
Expand All @@ -42,6 +42,12 @@ benchmark_threads_SOURCES = benchmark_threads.cpp
benchmark_nodelay_SOURCES = benchmark_nodelay.cpp
file_upload_SOURCES = file_upload.cpp
file_upload_with_callback_SOURCES = file_upload_with_callback.cpp
empty_response_example_SOURCES = empty_response_example.cpp
iovec_response_example_SOURCES = iovec_response_example.cpp
pipe_response_example_SOURCES = pipe_response_example.cpp
daemon_info_SOURCES = daemon_info.cpp
external_event_loop_SOURCES = external_event_loop.cpp
turbo_mode_SOURCES = turbo_mode.cpp

if HAVE_BAUTH
noinst_PROGRAMS += basic_authentication centralized_authentication
Expand All @@ -59,3 +65,9 @@ if HAVE_DAUTH
noinst_PROGRAMS += digest_authentication
digest_authentication_SOURCES = digest_authentication.cpp
endif

if HAVE_WEBSOCKET
noinst_PROGRAMS += websocket_echo
websocket_echo_SOURCES = websocket_echo.cpp
websocket_echo_LDADD = $(LDADD) -lmicrohttpd_ws
endif
59 changes: 59 additions & 0 deletions examples/daemon_info.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
This file is part of libhttpserver
Copyright (C) 2011-2019 Sebastiano Merlino

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA
*/

#include <iostream>
#include <memory>

#include <httpserver.hpp>

class hello_resource : public httpserver::http_resource {
public:
std::shared_ptr<httpserver::http_response> render_GET(const httpserver::http_request&) {
return std::make_shared<httpserver::string_response>("Hello, World!");
}
};

int main() {
// Use port 0 to let the OS assign an ephemeral port
httpserver::webserver ws = httpserver::create_webserver(0);

hello_resource hr;
ws.register_resource("/hello", &hr);
ws.start(false);

// Query daemon information
std::cout << "libmicrohttpd version: "
<< httpserver::http::http_utils::get_mhd_version() << std::endl;
std::cout << "Bound port: " << ws.get_bound_port() << std::endl;
std::cout << "Listen FD: " << ws.get_listen_fd() << std::endl;
std::cout << "Active connections: " << ws.get_active_connections() << std::endl;
std::cout << "HTTP 200 reason: "
<< httpserver::http::http_utils::reason_phrase(200) << std::endl;
std::cout << "HTTP 404 reason: "
<< httpserver::http::http_utils::reason_phrase(404) << std::endl;

std::cout << "\nServer running on port " << ws.get_bound_port()
<< ". Press Ctrl+C to stop." << std::endl;

// Block until interrupted
ws.sweet_kill();

return 0;
}
16 changes: 11 additions & 5 deletions examples/digest_authentication.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,21 @@
class digest_resource : public httpserver::http_resource {
public:
std::shared_ptr<httpserver::http_response> render_GET(const httpserver::http_request& req) {
using httpserver::http::http_utils;
if (req.get_digested_user() == "") {
return std::shared_ptr<httpserver::digest_auth_fail_response>(new httpserver::digest_auth_fail_response("FAIL", "test@example.com", MY_OPAQUE, true));
return std::make_shared<httpserver::digest_auth_fail_response>("FAIL", "test@example.com", MY_OPAQUE, true,
http_utils::http_ok, http_utils::text_plain, http_utils::digest_algorithm::MD5);
} else {
bool reload_nonce = false;
if (!req.check_digest_auth("test@example.com", "mypass", 300, &reload_nonce)) {
return std::shared_ptr<httpserver::digest_auth_fail_response>(new httpserver::digest_auth_fail_response("FAIL", "test@example.com", MY_OPAQUE, reload_nonce));
auto result = req.check_digest_auth("test@example.com", "mypass", 300, 0, http_utils::digest_algorithm::MD5);
if (result == http_utils::digest_auth_result::NONCE_STALE) {
return std::make_shared<httpserver::digest_auth_fail_response>("FAIL", "test@example.com", MY_OPAQUE, true,
http_utils::http_ok, http_utils::text_plain, http_utils::digest_algorithm::MD5);
} else if (result != http_utils::digest_auth_result::OK) {
return std::make_shared<httpserver::digest_auth_fail_response>("FAIL", "test@example.com", MY_OPAQUE, false,
http_utils::http_ok, http_utils::text_plain, http_utils::digest_algorithm::MD5);
}
}
return std::shared_ptr<httpserver::string_response>(new httpserver::string_response("SUCCESS", 200, "text/plain"));
return std::make_shared<httpserver::string_response>("SUCCESS", 200, "text/plain");
}
};

Expand Down
51 changes: 51 additions & 0 deletions examples/empty_response_example.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
This file is part of libhttpserver
Copyright (C) 2011-2019 Sebastiano Merlino

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA
*/

#include <memory>

#include <httpserver.hpp>

class no_content_resource : public httpserver::http_resource {
public:
std::shared_ptr<httpserver::http_response> render_DELETE(const httpserver::http_request&) {
// Return a 204 No Content response with no body
return std::make_shared<httpserver::empty_response>(
httpserver::http::http_utils::http_no_content);
}

std::shared_ptr<httpserver::http_response> render_HEAD(const httpserver::http_request&) {
// Return a HEAD-only response with headers but no body
auto response = std::make_shared<httpserver::empty_response>(
httpserver::http::http_utils::http_ok,
httpserver::empty_response::HEAD_ONLY);
response->with_header("X-Total-Count", "42");
return response;
}
};

int main() {
httpserver::webserver ws = httpserver::create_webserver(8080);

no_content_resource ncr;
ws.register_resource("/items", &ncr);
ws.start(true);

return 0;
}
67 changes: 67 additions & 0 deletions examples/external_event_loop.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
This file is part of libhttpserver
Copyright (C) 2011-2019 Sebastiano Merlino

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA
*/

#include <csignal>
#include <cstdint>
#include <iostream>
#include <memory>

#include <httpserver.hpp>

static volatile bool running = true;

void signal_handler(int) {
running = false;
}

class hello_resource : public httpserver::http_resource {
public:
std::shared_ptr<httpserver::http_response> render_GET(const httpserver::http_request&) {
return std::make_shared<httpserver::string_response>("Hello from external event loop!");
}
};

int main() {
signal(SIGINT, signal_handler);

httpserver::webserver ws = httpserver::create_webserver(8080);

hello_resource hr;
ws.register_resource("/hello", &hr);
ws.start(false);

std::cout << "Server running on port " << ws.get_bound_port() << std::endl;

// Drive the event loop externally using run_wait
while (running) {
// Block for up to 1000ms waiting for HTTP activity
ws.run_wait(1000);

// You can do other work here between iterations
}

std::cout << "\nShutting down..." << std::endl;

// Graceful shutdown: stop accepting new connections first
ws.quiesce();
ws.stop();

return 0;
}
Loading