Hello guys,

thank-you for your thorough review.  With Mark's help I've
dropped the original patch from patchwork, and am submitting an
updated one, hopefully addressing your comments.

Martin
>From 1c94f69c4602d7e2df31f03cc503f0c53d173bad Mon Sep 17 00:00:00 2001
From: Martin Cermak <[email protected]>
Date: Fri, 5 Dec 2025 10:42:07 +0100
Subject: [PATCH] PR33635:  Introduce debuginfod --home-redirect and
 --home-html

NEWS: New entry
debuginfod/debuginfod.cxx: Feature implementation
doc/debuginfod.8: Doc text
tests/Makefile.am: New testcase
tests/run-debuginfod-homesite.sh: New testcase

Signed-off-by: Martin Cermak <[email protected]>
---
 NEWS                             |  4 ++
 debuginfod/debuginfod.cxx        | 57 ++++++++++++++++++++++++---
 doc/debuginfod.8                 | 10 +++++
 tests/Makefile.am                |  4 +-
 tests/run-debuginfod-homesite.sh | 67 ++++++++++++++++++++++++++++++++
 5 files changed, 135 insertions(+), 7 deletions(-)
 create mode 100644 tests/run-debuginfod-homesite.sh

diff --git a/NEWS b/NEWS
index 922a15cc..587f7b61 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,7 @@
+debuginfod: Introduce --home-redirect and --home-html switches allowing
+            for redirecting to custom URL and/or serving a custom html
+            file, if document root is requested.  Related: PR33635.
+
 Version 0.194 "Manual Labour"
 
 debuginfod-find: Fixed caching bug preventing user-cancelled downloads
diff --git a/debuginfod/debuginfod.cxx b/debuginfod/debuginfod.cxx
index 8fc9426e..9796d312 100644
--- a/debuginfod/debuginfod.cxx
+++ b/debuginfod/debuginfod.cxx
@@ -484,6 +484,8 @@ static const struct argp_option options[] =
      "Number of seconds to limit metadata query run time, 0=unlimited.", 0 },
 #define ARGP_KEY_HTTP_ADDR 0x100D
    { "listen-address", ARGP_KEY_HTTP_ADDR, "ADDR", 0, "HTTP address to listen 
on.", 0 },
+   { "home-redirect", 'h', "URL", 0, "Custom homepage - redirect.", 0 },
+   { "home-html", 'H', "FILE", 0, "Custom homepage - htmlfile.", 0 },
    { NULL, 0, NULL, 0, NULL, 0 },
   };
 
@@ -543,6 +545,8 @@ static long scan_checkpoint = 256;
 static bool requires_koji_sigcache_mapping = false;
 #endif
 static unsigned metadata_maxtime_s = 5;
+static string cust_homepage_redirect = "";
+static string cust_homepage_file = "";
 
 static void set_metric(const string& key, double value);
 static void inc_metric(const string& key);
@@ -769,6 +773,12 @@ parse_opt (int key, char *arg,
       addr_info = arg;
       break;
       // case 'h': argp_state_help (state, stderr, 
ARGP_HELP_LONG|ARGP_HELP_EXIT_OK);
+    case 'h':
+      cust_homepage_redirect = arg;
+      break;
+    case 'H':
+      cust_homepage_file = arg;
+      break;
     default: return ARGP_ERR_UNKNOWN;
     }
 
@@ -3793,11 +3803,36 @@ handle_metadata (MHD_Connection* conn,
 static struct MHD_Response*
 handle_root (off_t* size)
 {
+  MHD_Response* r;
+  if (cust_homepage_file != "")
+    try
+      {
+        int fd = open (cust_homepage_file.c_str(), O_RDONLY);
+        if (fd != -1) {
+          struct stat buf;
+          stat (cust_homepage_file.c_str(), &buf);
+          r =  MHD_create_response_from_fd(buf.st_size, fd);
+          // NB: MHD owns and handles the fd from now.  Must not close()!
+          if (r != NULL)
+            {
+              *size = buf.st_size;
+              add_mhd_response_header (r, "Content-Type", "text/html");
+            }
+        } else {
+          throw libc_exception (errno, "cannot open file " + 
cust_homepage_file);
+        }
+        return r;
+      }
+    catch (const reportable_exception& e)
+      {
+        e.report(clog);
+      }
+
   static string version = "debuginfod (" + string (PACKAGE_NAME) + ") "
-                         + string (PACKAGE_VERSION);
-  MHD_Response* r = MHD_create_response_from_buffer (version.size (),
-                                                    (void *) version.c_str (),
-                                                    MHD_RESPMEM_PERSISTENT);
+                          + string (PACKAGE_VERSION);
+  r = MHD_create_response_from_buffer (version.size (),
+                                       (void *) version.c_str (),
+                                       MHD_RESPMEM_PERSISTENT);
   if (r != NULL)
     {
       *size = version.size ();
@@ -3985,8 +4020,18 @@ handler_cb (void * /*cls*/,
       if (webapi_cors)
         // add ACAO header for all successful requests
         add_mhd_response_header (r, "Access-Control-Allow-Origin", "*");
-      rc = MHD_queue_response (connection, MHD_HTTP_OK, r);
-      http_code = MHD_HTTP_OK;
+      if ((cust_homepage_redirect) != "" && (url1 == "/"))
+        {
+          // redirect to given custom --homepage
+          MHD_add_response_header(r, "Location", 
cust_homepage_redirect.c_str());
+          rc = MHD_queue_response (connection, MHD_HTTP_FOUND, r);
+          http_code = MHD_HTTP_FOUND;
+        }
+      else
+        {
+          rc = MHD_queue_response (connection, MHD_HTTP_OK, r);
+          http_code = MHD_HTTP_OK;
+        }
       MHD_destroy_response (r);
     }
   catch (const reportable_exception& e)
diff --git a/doc/debuginfod.8 b/doc/debuginfod.8
index d7744db1..ead3d3b1 100644
--- a/doc/debuginfod.8
+++ b/doc/debuginfod.8
@@ -312,6 +312,16 @@ from the Fedora koji sigcache rpm.sig files as opposed to 
the original RPM heade
 If a signature cannot be found in the sigcache rpm.sig file, the RPM will be
 tried as a fallback.
 
+.TP
+.B "\-\-home\-redirect"
+Allow for redirecting to a custom URL in case client requests the
+document root.
+
+.TP
+.B "\-\-home\-html"
+Allow for serving a custom text/html FILE in case client requests
+the document root.
+
 .TP
 .B "\-v"
 Increase verbosity of logging to the standard error file descriptor.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 15c32a85..3702444d 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -296,7 +296,8 @@ TESTS += run-srcfiles-self.sh \
         run-debuginfod-IXr.sh \
         run-debuginfod-client-profile.sh \
         run-debuginfod-find-metadata.sh \
-        run-debuginfod-longsource.sh
+        run-debuginfod-longsource.sh \
+        run-debuginfod-homesite.sh
 if LZMA
 TESTS += run-debuginfod-seekable.sh
 endif
@@ -636,6 +637,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \
             run-debuginfod-ima-verification.sh \
             run-debuginfod-find-metadata.sh \
             run-debuginfod-longsource.sh \
+            run-debuginfod-homesite.sh \
             debuginfod-rpms/fedora30/hello2-1.0-2.src.rpm \
             debuginfod-rpms/fedora30/hello2-1.0-2.x86_64.rpm \
             debuginfod-rpms/fedora30/hello2-debuginfo-1.0-2.x86_64.rpm \
diff --git a/tests/run-debuginfod-homesite.sh b/tests/run-debuginfod-homesite.sh
new file mode 100644
index 00000000..d107dddc
--- /dev/null
+++ b/tests/run-debuginfod-homesite.sh
@@ -0,0 +1,67 @@
+#!/usr/bin/env bash
+#
+# Copyright (C) 2022 Red Hat, Inc.
+# This file is part of elfutils.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# elfutils 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+type socat 2>/dev/null || exit 77
+
+. $srcdir/debuginfod-subr.sh  # includes set -e
+
+set -x
+
+# This variable is essential and ensures no time-race for claiming ports occurs
+# set base to a unique multiple of 100 not used in any other 
'run-debuginfod-*' test
+base=10200
+get_ports
+
+tempfiles vlog$PORT1
+errfiles vlog$PORT1
+
+# Test 1: Make sure attempt to open non-existent --home-html is handled 
gracefully
+rurl="https://sourceware.org/elfutils/Debuginfod.html";
+env LD_LIBRARY_PATH=$ldpath DEBUGINFOD_URLS= 
${abs_builddir}/../debuginfod/debuginfod \
+    $VERBOSE -p $PORT1 --home-html=non-existent.html --home-redirect=$rurl > 
vlog$PORT1 2>&1 &
+PID1=$!
+# Server must become ready
+wait_ready $PORT1 'ready' 1
+echo -e 'GET / HTTP/1.1\nHost: localhost\n' | socat - TCP:127.0.0.1:$PORT1 > 
response.txt
+tempfiles response.txt
+# If non-existent --home-html is passed, server should only send headers
+# incl. the --home-redirect in this case ...
+grep -F "Location: $rurl" response.txt
+# ... followed by the version id.
+tail -1 response.txt | grep -F 'debuginfod'
+kill $PID1
+wait $PID1
+
+# Test 2: Test valid --home-redirect
+echo "<html><body>hiya from debuginfod</body></html>" > home.html
+tempfiles home.html
+rurl="https://sourceware.org/elfutils/Debuginfod.html";
+env LD_LIBRARY_PATH=$ldpath DEBUGINFOD_URLS= 
${abs_builddir}/../debuginfod/debuginfod \
+    $VERBOSE -p $PORT1 --home-html=home.html --home-redirect=$rurl > 
vlog$PORT1 2>&1 &
+PID1=$!
+# Server must become ready
+wait_ready $PORT1 'ready' 1
+echo -e 'GET / HTTP/1.1\nHost: localhost\n' | socat - TCP:127.0.0.1:$PORT1 > 
response.txt
+tempfiles response.txt
+grep -F 'hiya from debuginfod' response.txt
+grep -F "Location: $rurl" response.txt
+kill $PID1
+wait $PID1
+
+PID1=0
+exit 0
-- 
2.51.1

Reply via email to