Hello, Please find the patch for pr28284 attached
Debuginfod and debuginfod clients are now equipped to send and receive http headers prefixed with X-DEBUGINFOD and print them in verbose mode for more context Noah Sanci
From 2d4902ca53b80b5cd5689a1ba77e4465c33fea64 Mon Sep 17 00:00:00 2001 From: Noah Sanci <nsa...@redhat.com> Date: Wed, 15 Jun 2022 10:07:29 -0400 Subject: [PATCH] PR28284 - Debuginfod header functionality implemented --- debuginfod/debuginfod-client.c | 14 ++++++- debuginfod/debuginfod-find.c | 3 ++ debuginfod/debuginfod.cxx | 18 +++++++++ debuginfod/debuginfod.h.in | 4 ++ debuginfod/libdebuginfod.map | 3 ++ doc/debuginfod_find_debuginfo.3 | 13 +++++++ doc/debuginfod_get_headers.3 | 2 + tests/run-debuginfod-response-headers.sh | 48 +++++++++++++++++++++--- 8 files changed, 97 insertions(+), 8 deletions(-) create mode 100644 doc/debuginfod_get_headers.3 diff --git a/debuginfod/debuginfod-client.c b/debuginfod/debuginfod-client.c index b7b65aff..a3565f57 100644 --- a/debuginfod/debuginfod-client.c +++ b/debuginfod/debuginfod-client.c @@ -501,6 +501,12 @@ header_callback (char * buffer, size_t size, size_t numitems, void * userdata) { if (size != 1) return 0; + // X-DEBUGINFOD is 11 characters long. + // Some basic checks to ensure the headers received are of the expected format + if ( strncmp(buffer, "X-DEBUGINFOD", 11) || buffer[numitems-1] != '\n' + || (buffer == strstr(buffer, ":")) ){ + return numitems; + } /* Temporary buffer for realloc */ char *temp = NULL; struct handle_data *data = (struct handle_data *) userdata; @@ -1111,8 +1117,6 @@ debuginfod_query_server (debuginfod_client *c, if (c->winning_headers == NULL) { c->winning_headers = data[committed_to].response_data; - if (vfd >= 0 && c->winning_headers != NULL) - dprintf(vfd, "\n%s", c->winning_headers); data[committed_to].response_data = NULL; data[committed_to].response_data_size = 0; } @@ -1542,6 +1546,12 @@ debuginfod_get_url(debuginfod_client *client) return client->url; } +const char * +debuginfod_get_headers(debuginfod_client *client) +{ + return client->winning_headers; +} + void debuginfod_end (debuginfod_client *client) { diff --git a/debuginfod/debuginfod-find.c b/debuginfod/debuginfod-find.c index f60b5463..fb1f294c 100644 --- a/debuginfod/debuginfod-find.c +++ b/debuginfod/debuginfod-find.c @@ -215,6 +215,9 @@ main(int argc, char** argv) if (verbose) { + const char* headers = debuginfod_get_headers(client); + if (headers) + fprintf(stderr, "Headers:\n%s", headers); const char* url = debuginfod_get_url (client); if (url != NULL) fprintf(stderr, "Downloaded from %s\n", url); diff --git a/debuginfod/debuginfod.cxx b/debuginfod/debuginfod.cxx index 51f4302b..d64c5965 100644 --- a/debuginfod/debuginfod.cxx +++ b/debuginfod/debuginfod.cxx @@ -2085,6 +2085,24 @@ and will not query the upstream servers"); { add_mhd_response_header (r, "Content-Type", "application/octet-stream"); + const char * hdrs = debuginfod_get_headers(client); + string header_dup; + if (hdrs) + header_dup = string(hdrs); + size_t pos = 0; + // Clean winning headers to add all X-DEBUGINFOD lines to the package we'll send + while( (pos = header_dup.find("X-DEBUGINFOD")) != string::npos) + { + // Focus on where X-DEBUGINFOD- begins + header_dup = header_dup.substr(pos); + size_t newline = header_dup.find('\n'); + if (newline == string::npos) + break; + add_mhd_response_header(r, header_dup.substr(0,header_dup.find(':')).c_str(), + header_dup.substr(header_dup.find(':')).c_str()); + header_dup = header_dup.substr(newline); + } + add_mhd_last_modified (r, s.st_mtime); if (verbose > 1) obatched(clog) << "serving file from upstream debuginfod/cache" << endl; diff --git a/debuginfod/debuginfod.h.in b/debuginfod/debuginfod.h.in index c358df4d..6ae8b91c 100644 --- a/debuginfod/debuginfod.h.in +++ b/debuginfod/debuginfod.h.in @@ -93,6 +93,10 @@ void* debuginfod_get_user_data (debuginfod_client *client); /* Get the current or last active URL, if known. */ const char* debuginfod_get_url (debuginfod_client *client); +/* Returns all headers sent to this client which were prefixed + * with X-DEBUGINFOD */ +const char* debuginfod_get_headers(debuginfod_client *client); + /* Add an outgoing HTTP request "Header: Value". Copies string. */ int debuginfod_add_http_header (debuginfod_client *client, const char* header); diff --git a/debuginfod/libdebuginfod.map b/debuginfod/libdebuginfod.map index 7d2f5882..f95b5b9a 100644 --- a/debuginfod/libdebuginfod.map +++ b/debuginfod/libdebuginfod.map @@ -18,3 +18,6 @@ ELFUTILS_0.179 { ELFUTILS_0.183 { debuginfod_set_verbose_fd; } ELFUTILS_0.179; +ELFUTILS_0.189 { + debuginfod_get_headers; +} ELFUTILS_0.183; diff --git a/doc/debuginfod_find_debuginfo.3 b/doc/debuginfod_find_debuginfo.3 index 30cef3c1..984fda12 100644 --- a/doc/debuginfod_find_debuginfo.3 +++ b/doc/debuginfod_find_debuginfo.3 @@ -58,6 +58,7 @@ OPTIONAL FUNCTIONS .BI "const char* debuginfod_get_url(debuginfod_client *" client ");" .BI "int debuginfod_add_http_header(debuginfod_client *" client "," .BI " const char* " header ");" +.BI "const char* debuginfod_get_headers(debuginfod_client *" client ");" .SH DESCRIPTION @@ -198,6 +199,18 @@ By default, the library adds a descriptive \fIUser-Agent:\fP header to outgoing requests. If the client application adds a header with the same name, this default is suppressed. +.BR \%debuginfod_get_headers () +may be called with a debuginfod client. This function will return the +http response headers prefixed with +.BR X-DEBUGINFOD +received from the first handle to get a response from a debuginfod server. +Note that all other http headers aren't stored in the libcurl header +callback function since they aren't of as much interest. The caller should +copy the returned string if it is needed beyond the release of the client object. +The returned string may be NULL if no headers are prefixed with +.BR X-DEBUGINFOD +\. + .SH "MACROS" .SS "DEBUGINFOD_SONAME" diff --git a/doc/debuginfod_get_headers.3 b/doc/debuginfod_get_headers.3 new file mode 100644 index 00000000..1db55982 --- /dev/null +++ b/doc/debuginfod_get_headers.3 @@ -0,0 +1,2 @@ +.so man3/debuginfod_find_debuginfo.3 + diff --git a/tests/run-debuginfod-response-headers.sh b/tests/run-debuginfod-response-headers.sh index 62c43887..e5698cc9 100755 --- a/tests/run-debuginfod-response-headers.sh +++ b/tests/run-debuginfod-response-headers.sh @@ -73,17 +73,21 @@ rm -rf $DEBUGINFOD_CACHE_PATH env DEBUGINFOD_URLS="http://127.0.0.1:"$PORT1 LD_LIBRARY_PATH=$ldpath ${abs_top_builddir}/debuginfod/debuginfod-find\ -vvv executable F/prog > vlog-find$PORT1.1 2>&1 tempfiles vlog-find$PORT1.1 -grep 'Content-Length: ' vlog-find$PORT1.1 -grep 'X-DEBUGINFOD-FILE: ' vlog-find$PORT1.1 -grep 'X-DEBUGINFOD-SIZE: ' vlog-find$PORT1.1 +errfiles vlog-find$PORT1.1 +cat vlog-find$PORT1.1 +grep 'Headers:' vlog-find$PORT1.1 +grep 'X-DEBUGINFOD-FILE: prog' vlog-find$PORT1.1 +grep 'X-DEBUGINFOD-SIZE: ' vlog-find$PORT1.1 # Check to see if an executable file located in an archive prints the file's description and archive env DEBUGINFOD_URLS="http://127.0.0.1:"$PORT1 LD_LIBRARY_PATH=$ldpath ${abs_top_builddir}/debuginfod/debuginfod-find\ -vvv executable c36708a78618d597dee15d0dc989f093ca5f9120 > vlog-find$PORT1.2 2>&1 tempfiles vlog-find$PORT1.2 -grep 'Content-Length: ' vlog-find$PORT1.2 -grep 'X-DEBUGINFOD-FILE: ' vlog-find$PORT1.2 -grep 'X-DEBUGINFOD-SIZE: ' vlog-find$PORT1.2 +errfiles vlog-find$PORT1.2 +cat vlog-find$PORT1.2 +grep 'Headers:' vlog-find$PORT1.2 +grep 'X-DEBUGINFOD-FILE: ' vlog-find$PORT1.2 +grep 'X-DEBUGINFOD-SIZE: ' vlog-find$PORT1.2 grep 'X-DEBUGINFOD-ARCHIVE: ' vlog-find$PORT1.2 # Check that X-DEBUGINFOD-SIZE matches the size of each file @@ -94,6 +98,38 @@ do test $st_size -eq $x_debuginfod_size done +rm -rf $DEBUGINFOD_CACHE_PATH +BUILDID=`env LD_LIBRARY_PATH=$ldpath ${abs_builddir}/../src/readelf \ + -a F/prog | grep 'Build ID' | cut -d ' ' -f 7` +netcat_dir="buildid/$BUILDID/" +mkdir -p ${PWD}/$netcat_dir +cp F/prog ${PWD}/$netcat_dir/executable +tempfiles F/prog + +# Netcat dies after answering the request +nc -l -p $PORT2 -c 'echo -e "HTTP/1.1 200 OK\nX-DEBUGINFOD-SIZE: ba:d_size\nX-DEBUGINFOD-\rFILE:\=\+ \r213\n\n $(date)"' & < ${PWD}/$netcat_dir"executable" & +# Wait until the netcat port is in use. Otherwise debuginfod-find can query +# before netcat is ready. +SECONDS=0 +nc_start=$SECONDS +while [ ! $(lsof -i -P -n | grep LISTEN | grep "nc.*$PORT2") ] +do + # If it takes longer than 5 seconds for netcat to start up, then fail + duration=$(( SECONDS - nc_start )) + if [ $SECONDS -gt 5 ] + then + err + fi +done + +env DEBUGINFOD_URLS="http://127.0.0.1:"$PORT2 LD_LIBRARY_PATH=$ldpath ${abs_top_builddir}/debuginfod/debuginfod-find\ + -vvv executable $BUILDID > vlog-find$PORT2 2>&1 +errfiles vlog-find$PORT2 +tempfiles vlog-find$PORT2 +cat vlog-find$PORT2 | grep "X-DEBUGINFOD-" +rm -f "$netcat_dir"executable +rmdir -p $netcat_dir + kill $PID1 wait $PID1 PID1=0 -- 2.36.1