Hi -

I'm planning to commit this shortly:

>From 4ebefc8f3b4b8fb68a55c960e70122fda50a0fb9 Mon Sep 17 00:00:00 2001
From: "Frank Ch. Eigler" <f...@redhat.com>
Date: Sat, 7 Dec 2024 15:01:54 -0500
Subject: [PATCH] debuginfod: add CORS response headers and OPTIONS method

From: Henning Meyer <hmeyer...@gmail.com>

CORS is the Cross-Origin-Resource-Sharing mechanism explained at
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS 1. by default
JavaScript code from Website A cannot request arbitrary resources from
website B, these are called cross-origin-requests 2. The browser
performs what is called a preflight check, this the OPTIONS method 3.
the response allows website B fine-grained control over what the web
browser should allow 4. Setting "Access-Control-Allow-Origin: *" tells
the web browser to allow all access, e.g. the same behavior you get with
curl or debuginfod-find The website mentions that the corresponding spec
has been changed, such that preflight requests are no longer necessary,
but in the browsers I use today (Firefox 132 and Chromium 131) they are
still necessary.

I have confirmed that I can use debuginfod with this patch from my web
application at https://core-explorer.github.io/cdx-type/

FChE simplified the code and added a few quick "curl -i | grep" tests
to confirm the new headers are there.

Signed-off-by: Henning Meyer <hmeyer...@gmail.com>
Signed-off-by: Frank Ch. Eigler <f...@redhat.com>
---
 debuginfod/debuginfod.cxx                  | 35 ++++++++++++++++++++--
 tests/run-debuginfod-federation-metrics.sh |  3 ++
 tests/run-debuginfod-find-metadata.sh      |  1 +
 3 files changed, 36 insertions(+), 3 deletions(-)

diff --git a/debuginfod/debuginfod.cxx b/debuginfod/debuginfod.cxx
index 4bb517bde80f..fbcd0f627dc8 100644
--- a/debuginfod/debuginfod.cxx
+++ b/debuginfod/debuginfod.cxx
@@ -3785,6 +3785,23 @@ handle_root (off_t* size)
 }
 
 
+static struct MHD_Response*
+handle_options (off_t* size)
+{
+  static char empty_body[] = " ";
+  MHD_Response* r = MHD_create_response_from_buffer (1, empty_body,
+                                                     MHD_RESPMEM_PERSISTENT);
+  if (r != NULL)
+    {
+      *size = 1;
+      add_mhd_response_header (r, "Access-Control-Allow-Origin", "*");
+      add_mhd_response_header (r, "Access-Control-Allow-Methods", "GET, 
OPTIONS");
+      add_mhd_response_header (r, "Access-Control-Allow-Headers", 
"cache-control");
+    }
+  return r;
+}
+
+
 ////////////////////////////////////////////////////////////////////////
 
 
@@ -3838,8 +3855,17 @@ handler_cb (void * /*cls*/,
 
   try
     {
-      if (string(method) != "GET")
-        throw reportable_exception(400, "we support GET only");
+      if (method == string("OPTIONS"))
+        {
+          inc_metric("http_requests_total", "type", method);
+          r = handle_options(& http_size);
+          rc = MHD_queue_response (connection, MHD_HTTP_OK, r);
+          http_code = MHD_HTTP_OK;
+          MHD_destroy_response (r);
+          return rc;
+        }
+      else if (string(method) != "GET")
+        throw reportable_exception(400, "we support OPTIONS+GET only");
 
       /* Start decoding the URL. */
       size_t slash1 = url_copy.find('/', 1);
@@ -3887,7 +3913,7 @@ handler_cb (void * /*cls*/,
 
           // get the resulting fd so we can report its size
           int fd;
-          r = handle_buildid(connection, buildid, artifacttype, suffix, &fd);
+          r = handle_buildid (connection, buildid, artifacttype, suffix, &fd);
           if (r)
             {
               struct stat fs;
@@ -3934,6 +3960,8 @@ handler_cb (void * /*cls*/,
           throw reportable_exception(406, "File too large, max size=" + 
std::to_string(maxsize));
         }
 
+      // 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;
       MHD_destroy_response (r);
@@ -4023,6 +4051,7 @@ dwarf_extract_source_paths (Elf *elf, set<string>& 
debug_sourcefiles)
             {
               string artifacttype = "debuginfo";
               r = handle_buildid (0, buildid, artifacttype, "", &alt_fd);
+              // NB: no need for ACAO etc. headers; this is not getting sent 
to a client 
             }
           catch (const reportable_exception& e)
             {
diff --git a/tests/run-debuginfod-federation-metrics.sh 
b/tests/run-debuginfod-federation-metrics.sh
index 60fe69ca4f25..eef800010935 100755
--- a/tests/run-debuginfod-federation-metrics.sh
+++ b/tests/run-debuginfod-federation-metrics.sh
@@ -153,6 +153,8 @@ testrun ${abs_builddir}/debuginfod_build_id_find -e F/prog 1
 curl -s http://127.0.0.1:$PORT1/badapi
 curl -s http://127.0.0.1:$PORT1/metrics
 curl -s http://127.0.0.1:$PORT2/metrics
+curl -i -s http://127.0.0.1:$PORT1/metrics | grep -i 
access.control.allow.origin:
+curl -X OPTIONS -i -s http://127.0.0.1:$PORT1/ | grep -i 
access.control.allow.origin:
 curl -s http://127.0.0.1:$PORT1/metrics | grep -q 
'http_responses_total.*result.*error'
 curl -s http://127.0.0.1:$PORT2/metrics | grep -q 
'http_responses_total.*result.*upstream'
 curl -s http://127.0.0.1:$PORT1/metrics | grep 
'http_responses_duration_milliseconds_count'
@@ -181,6 +183,7 @@ rm -f .client_cache*/$BUILDID/debuginfo
 testrun ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo $BUILDID
 testrun ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo $BUILDID
 testrun ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo $BUILDID
+curl -i -s http://127.0.0.1:$PORT2/buildid/$BUILDID/debuginfo | grep -i 
access.control.allow.origin:
 rm -f .client_cache*/$BUILDID/debuginfo
 testrun ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo $BUILDID
 
diff --git a/tests/run-debuginfod-find-metadata.sh 
b/tests/run-debuginfod-find-metadata.sh
index 78a34f09490f..041d08233281 100755
--- a/tests/run-debuginfod-find-metadata.sh
+++ b/tests/run-debuginfod-find-metadata.sh
@@ -79,6 +79,7 @@ test $N_FOUND -eq 2
 
 # Query via the webapi as well
 curl http://127.0.0.1:$PORT2'/metadata?key=glob&value=/usr/bin/*hi*'
+curl -s -i http://127.0.0.1:$PORT2'/metadata?key=glob&value=/usr/bin/*hi*' | 
grep -i access.control.allow.origin:
 test `curl -s http://127.0.0.1:$PORT2'/metadata?key=glob&value=/usr/bin/*hi*' 
| jq '.results[0].buildid == "f17a29b5a25bd4960531d82aa6b07c8abe84fa66"'` = 
'true'
 test `curl -s http://127.0.0.1:$PORT2'/metadata?key=glob&value=/usr/bin/*hi*' 
| jq '.results[0].file == "/usr/bin/hithere"'` = 'true'
 test `curl -s http://127.0.0.1:$PORT2'/metadata?key=glob&value=/usr/bin/*hi*' 
| jq '.results[0].archive | test(".*hithere.*deb")'` = 'true'
-- 
2.47.1

Reply via email to