Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
test: add unit test for uri_log null/empty/valid uri handling
Adds test/unit/uri_log_test.cpp to lock in the fix for issue #371. The
test calls uri_log() directly (re-declaring the symbol since it has no
public header) and verifies three cases:

  - null uri does not throw and yields an empty complete_uri
  - valid uri is stored verbatim
  - empty uri is stored verbatim

The first case is the regression check: against the unfixed code,
running the test crashes the process (SIGSEGV from dereferencing the
null pointer inside std::string's assignment operator on libstdc++ 13;
on the older libstdc++ 10 from the bug report it threw std::logic_error
and aborted via std::terminate). With the fix in place, all three sub-
tests pass cleanly.

The new test target needs an explicit -lmicrohttpd in its link line
because it instantiates ~modded_request() directly, which references
MHD_destroy_post_processor; the default LDADD only pulls libmicrohttpd
in transitively via libhttpserver.la, and modern ld enforces
--no-copy-dt-needed-entries.
  • Loading branch information
etr committed Apr 7, 2026
commit 9fde1286aaaa7d1c253f3ba6d1f671701dd74c55
7 changes: 6 additions & 1 deletion test/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ LDADD += -lcurl

AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/src/httpserver/
METASOURCES = AUTO
check_PROGRAMS = basic file_upload http_utils threaded nodelay string_utilities http_endpoint ban_system ws_start_stop authentication deferred http_resource http_response create_webserver
check_PROGRAMS = basic file_upload http_utils threaded nodelay string_utilities http_endpoint ban_system ws_start_stop authentication deferred http_resource http_response create_webserver uri_log

MOSTLYCLEANFILES = *.gcda *.gcno *.gcov

Expand All @@ -44,6 +44,11 @@ nodelay_SOURCES = integ/nodelay.cpp
http_resource_SOURCES = unit/http_resource_test.cpp
http_response_SOURCES = unit/http_response_test.cpp
create_webserver_SOURCES = unit/create_webserver_test.cpp
uri_log_SOURCES = unit/uri_log_test.cpp
# uri_log_test directly references libmicrohttpd via ~modded_request(), so
# it needs an explicit -lmicrohttpd in its link line on top of the default
# LDADD (modern ld enforces --no-copy-dt-needed-entries).
uri_log_LDADD = $(LDADD) -lmicrohttpd

noinst_HEADERS = littletest.hpp
AM_CXXFLAGS += -Wall -fPIC -Wno-overloaded-virtual
Expand Down
86 changes: 86 additions & 0 deletions test/unit/uri_log_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
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 <string>

#include "httpserver.hpp"
#include "httpserver/details/modded_request.hpp"

#include "./littletest.hpp"

// uri_log is the MHD URI-log callback defined in src/webserver.cpp. It is
// exported from the library but has no public header, so we re-declare its
// signature here. MHD_Connection is opaque to this test - we only ever pass
// nullptr, mirroring how MHD itself may invoke the callback before the
// connection is fully initialised.
namespace httpserver {
void* uri_log(void* cls, const char* uri, struct MHD_Connection* con);
} // namespace httpserver

LT_BEGIN_SUITE(uri_log_suite)
void set_up() {
}

void tear_down() {
}
LT_END_SUITE(uri_log_suite)

// Regression test for issue #371: under load (port scans, half-open
// connections, non-HTTP traffic on the listening port) MHD may invoke the
// URI-log callback with a null uri pointer before the request line has
// been parsed. The previous implementation assigned the raw pointer into
// std::string, which throws std::logic_error and aborts the process via
// std::terminate because the throw escapes a C callback.
LT_BEGIN_AUTO_TEST(uri_log_suite, null_uri_does_not_throw)
void* raw = nullptr;
LT_CHECK_NOTHROW(raw = httpserver::uri_log(nullptr, nullptr, nullptr));
LT_CHECK(raw != nullptr);

auto* mr = static_cast<httpserver::details::modded_request*>(raw);
LT_CHECK_EQ(mr->complete_uri, std::string(""));
delete mr;
LT_END_AUTO_TEST(null_uri_does_not_throw)

// Sanity check that the happy path still records the URI as before.
LT_BEGIN_AUTO_TEST(uri_log_suite, valid_uri_is_stored)
const char* uri = "/some/path?with=query";
void* raw = httpserver::uri_log(nullptr, uri, nullptr);
LT_CHECK(raw != nullptr);

auto* mr = static_cast<httpserver::details::modded_request*>(raw);
LT_CHECK_EQ(mr->complete_uri, std::string(uri));
delete mr;
LT_END_AUTO_TEST(valid_uri_is_stored)

// Empty (but non-null) URI should be stored verbatim - this is the same
// observable state the null-uri path now produces, so route matching falls
// through to a 404 in both cases.
LT_BEGIN_AUTO_TEST(uri_log_suite, empty_uri_is_stored)
void* raw = httpserver::uri_log(nullptr, "", nullptr);
LT_CHECK(raw != nullptr);

auto* mr = static_cast<httpserver::details::modded_request*>(raw);
LT_CHECK_EQ(mr->complete_uri, std::string(""));
delete mr;
LT_END_AUTO_TEST(empty_uri_is_stored)

LT_BEGIN_AUTO_TEST_ENV()
AUTORUN_TESTS()
LT_END_AUTO_TEST_ENV()
Loading