diff options
author | Noah Sanci <nsanci@redhat.com> | 2022-06-15 10:07:29 -0400 |
---|---|---|
committer | Frank Ch. Eigler <fche@redhat.com> | 2022-09-06 11:32:13 -0400 |
commit | bbc2ca6d553f0ce3e670303ac9a3c764cf10d779 (patch) | |
tree | b08f81afb310c8c46cffdbeeb8e7881f7401573f | |
parent | debuginfod: Use auto-sized connection pool when -C is not given with arg (diff) | |
download | elfutils-bbc2ca6d553f0ce3e670303ac9a3c764cf10d779.tar.gz elfutils-bbc2ca6d553f0ce3e670303ac9a3c764cf10d779.tar.bz2 elfutils-bbc2ca6d553f0ce3e670303ac9a3c764cf10d779.tar.xz |
PR28284 - Debuginfod header functionality implemented
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
Signed-off-by: Noah Sanci <nsanci@redhat.com>
-rw-r--r-- | debuginfod/ChangeLog | 14 | ||||
-rw-r--r-- | debuginfod/debuginfod-client.c | 14 | ||||
-rw-r--r-- | debuginfod/debuginfod-find.c | 3 | ||||
-rw-r--r-- | debuginfod/debuginfod.cxx | 18 | ||||
-rw-r--r-- | debuginfod/debuginfod.h.in | 4 | ||||
-rw-r--r-- | debuginfod/libdebuginfod.map | 3 | ||||
-rw-r--r-- | doc/ChangeLog | 5 | ||||
-rw-r--r-- | doc/debuginfod_find_debuginfo.3 | 13 | ||||
-rw-r--r-- | doc/debuginfod_get_headers.3 | 2 | ||||
-rw-r--r-- | tests/ChangeLog | 6 | ||||
-rwxr-xr-x | tests/run-debuginfod-response-headers.sh | 48 |
11 files changed, 122 insertions, 8 deletions
diff --git a/debuginfod/ChangeLog b/debuginfod/ChangeLog index c692a389..8c843f3a 100644 --- a/debuginfod/ChangeLog +++ b/debuginfod/ChangeLog | |||
@@ -1,3 +1,17 @@ | |||
1 | 2022-07-15 Noah Sanci <nsanci@redhat.com> | ||
2 | |||
3 | * debuginfod-client.c (header_callback): Handle headers without | ||
4 | X-DEBUGINFOD prefix. | ||
5 | (debuginfod_query_server): Removed verbose printing headers when | ||
6 | undesired. | ||
7 | (debuginfod_get_headers): Created. | ||
8 | * debuginfod-find.c (main): Verboes printing headers. | ||
9 | * debuginfod.cxx (handle_buildid): Add headers prefixed with | ||
10 | X-DEBUGINFOD from federated servers to this server's response | ||
11 | headers. | ||
12 | * debuginfod.h.in (debuginfod_get_headers): Created. | ||
13 | * libdebuginfod.map: New elfutils version added. | ||
14 | |||
1 | 2022-09-02 Aaron Merey <amerey@redhat.com> | 15 | 2022-09-02 Aaron Merey <amerey@redhat.com> |
2 | 16 | ||
3 | * debuginfod.cxx (parse_opt): If '-C' is given with no arg, do not | 17 | * debuginfod.cxx (parse_opt): If '-C' is given with no arg, do not |
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) | |||
501 | { | 501 | { |
502 | if (size != 1) | 502 | if (size != 1) |
503 | return 0; | 503 | return 0; |
504 | // X-DEBUGINFOD is 11 characters long. | ||
505 | // Some basic checks to ensure the headers received are of the expected format | ||
506 | if ( strncmp(buffer, "X-DEBUGINFOD", 11) || buffer[numitems-1] != '\n' | ||
507 | || (buffer == strstr(buffer, ":")) ){ | ||
508 | return numitems; | ||
509 | } | ||
504 | /* Temporary buffer for realloc */ | 510 | /* Temporary buffer for realloc */ |
505 | char *temp = NULL; | 511 | char *temp = NULL; |
506 | struct handle_data *data = (struct handle_data *) userdata; | 512 | struct handle_data *data = (struct handle_data *) userdata; |
@@ -1111,8 +1117,6 @@ debuginfod_query_server (debuginfod_client *c, | |||
1111 | if (c->winning_headers == NULL) | 1117 | if (c->winning_headers == NULL) |
1112 | { | 1118 | { |
1113 | c->winning_headers = data[committed_to].response_data; | 1119 | c->winning_headers = data[committed_to].response_data; |
1114 | if (vfd >= 0 && c->winning_headers != NULL) | ||
1115 | dprintf(vfd, "\n%s", c->winning_headers); | ||
1116 | data[committed_to].response_data = NULL; | 1120 | data[committed_to].response_data = NULL; |
1117 | data[committed_to].response_data_size = 0; | 1121 | data[committed_to].response_data_size = 0; |
1118 | } | 1122 | } |
@@ -1542,6 +1546,12 @@ debuginfod_get_url(debuginfod_client *client) | |||
1542 | return client->url; | 1546 | return client->url; |
1543 | } | 1547 | } |
1544 | 1548 | ||
1549 | const char * | ||
1550 | debuginfod_get_headers(debuginfod_client *client) | ||
1551 | { | ||
1552 | return client->winning_headers; | ||
1553 | } | ||
1554 | |||
1545 | void | 1555 | void |
1546 | debuginfod_end (debuginfod_client *client) | 1556 | debuginfod_end (debuginfod_client *client) |
1547 | { | 1557 | { |
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) | |||
215 | 215 | ||
216 | if (verbose) | 216 | if (verbose) |
217 | { | 217 | { |
218 | const char* headers = debuginfod_get_headers(client); | ||
219 | if (headers) | ||
220 | fprintf(stderr, "Headers:\n%s", headers); | ||
218 | const char* url = debuginfod_get_url (client); | 221 | const char* url = debuginfod_get_url (client); |
219 | if (url != NULL) | 222 | if (url != NULL) |
220 | fprintf(stderr, "Downloaded from %s\n", url); | 223 | fprintf(stderr, "Downloaded from %s\n", url); |
diff --git a/debuginfod/debuginfod.cxx b/debuginfod/debuginfod.cxx index 8680c048..27b671d3 100644 --- a/debuginfod/debuginfod.cxx +++ b/debuginfod/debuginfod.cxx | |||
@@ -2093,6 +2093,24 @@ and will not query the upstream servers"); | |||
2093 | { | 2093 | { |
2094 | add_mhd_response_header (r, "Content-Type", | 2094 | add_mhd_response_header (r, "Content-Type", |
2095 | "application/octet-stream"); | 2095 | "application/octet-stream"); |
2096 | const char * hdrs = debuginfod_get_headers(client); | ||
2097 | string header_dup; | ||
2098 | if (hdrs) | ||
2099 | header_dup = string(hdrs); | ||
2100 | size_t pos = 0; | ||
2101 | // Clean winning headers to add all X-DEBUGINFOD lines to the package we'll send | ||
2102 | while( (pos = header_dup.find("X-DEBUGINFOD")) != string::npos) | ||
2103 | { | ||
2104 | // Focus on where X-DEBUGINFOD- begins | ||
2105 | header_dup = header_dup.substr(pos); | ||
2106 | size_t newline = header_dup.find('\n'); | ||
2107 | if (newline == string::npos) | ||
2108 | break; | ||
2109 | add_mhd_response_header(r, header_dup.substr(0,header_dup.find(':')).c_str(), | ||
2110 | header_dup.substr(header_dup.find(':')).c_str()); | ||
2111 | header_dup = header_dup.substr(newline); | ||
2112 | } | ||
2113 | |||
2096 | add_mhd_last_modified (r, s.st_mtime); | 2114 | add_mhd_last_modified (r, s.st_mtime); |
2097 | if (verbose > 1) | 2115 | if (verbose > 1) |
2098 | obatched(clog) << "serving file from upstream debuginfod/cache" << endl; | 2116 | 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); | |||
93 | /* Get the current or last active URL, if known. */ | 93 | /* Get the current or last active URL, if known. */ |
94 | const char* debuginfod_get_url (debuginfod_client *client); | 94 | const char* debuginfod_get_url (debuginfod_client *client); |
95 | 95 | ||
96 | /* Returns all headers sent to this client which were prefixed | ||
97 | * with X-DEBUGINFOD */ | ||
98 | const char* debuginfod_get_headers(debuginfod_client *client); | ||
99 | |||
96 | /* Add an outgoing HTTP request "Header: Value". Copies string. */ | 100 | /* Add an outgoing HTTP request "Header: Value". Copies string. */ |
97 | int debuginfod_add_http_header (debuginfod_client *client, const char* header); | 101 | int debuginfod_add_http_header (debuginfod_client *client, const char* header); |
98 | 102 | ||
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 { | |||
18 | ELFUTILS_0.183 { | 18 | ELFUTILS_0.183 { |
19 | debuginfod_set_verbose_fd; | 19 | debuginfod_set_verbose_fd; |
20 | } ELFUTILS_0.179; | 20 | } ELFUTILS_0.179; |
21 | ELFUTILS_0.189 { | ||
22 | debuginfod_get_headers; | ||
23 | } ELFUTILS_0.183; | ||
diff --git a/doc/ChangeLog b/doc/ChangeLog index 3fff1a84..c2a01a04 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog | |||
@@ -1,3 +1,8 @@ | |||
1 | 2022-07-15 Noah Sanci <nsanci@redhat.com> | ||
2 | * debuginfod_find_debuginfo.3: Explained debuginfod_get_headers | ||
3 | usage. | ||
4 | * debuginfod_get_headers.3: Created. | ||
5 | |||
1 | 2022-09-02 Aaron Merey <amerey@redhat.com> | 6 | 2022-09-02 Aaron Merey <amerey@redhat.com> |
2 | 7 | ||
3 | * debuginfod.8 (-C): Update description. | 8 | * debuginfod.8 (-C): Update description. |
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 | |||
58 | .BI "const char* debuginfod_get_url(debuginfod_client *" client ");" | 58 | .BI "const char* debuginfod_get_url(debuginfod_client *" client ");" |
59 | .BI "int debuginfod_add_http_header(debuginfod_client *" client "," | 59 | .BI "int debuginfod_add_http_header(debuginfod_client *" client "," |
60 | .BI " const char* " header ");" | 60 | .BI " const char* " header ");" |
61 | .BI "const char* debuginfod_get_headers(debuginfod_client *" client ");" | ||
61 | 62 | ||
62 | .SH DESCRIPTION | 63 | .SH DESCRIPTION |
63 | 64 | ||
@@ -198,6 +199,18 @@ By default, the library adds a descriptive \fIUser-Agent:\fP | |||
198 | header to outgoing requests. If the client application adds | 199 | header to outgoing requests. If the client application adds |
199 | a header with the same name, this default is suppressed. | 200 | a header with the same name, this default is suppressed. |
200 | 201 | ||
202 | .BR \%debuginfod_get_headers () | ||
203 | may be called with a debuginfod client. This function will return the | ||
204 | http response headers prefixed with | ||
205 | .BR X-DEBUGINFOD | ||
206 | received from the first handle to get a response from a debuginfod server. | ||
207 | Note that all other http headers aren't stored in the libcurl header | ||
208 | callback function since they aren't of as much interest. The caller should | ||
209 | copy the returned string if it is needed beyond the release of the client object. | ||
210 | The returned string may be NULL if no headers are prefixed with | ||
211 | .BR X-DEBUGINFOD | ||
212 | \. | ||
213 | |||
201 | .SH "MACROS" | 214 | .SH "MACROS" |
202 | 215 | ||
203 | .SS "DEBUGINFOD_SONAME" | 216 | .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 @@ | |||
1 | .so man3/debuginfod_find_debuginfo.3 | ||
2 | |||
diff --git a/tests/ChangeLog b/tests/ChangeLog index d2952cc9..659bfa19 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog | |||
@@ -1,3 +1,9 @@ | |||
1 | 2022-07-15 Noah Sanci <nsanci@redhat.com> | ||
2 | |||
3 | * run-debuginfod-response-headers.sh: Added test | ||
4 | to ensure that federated servers pass headers down to | ||
5 | queried server. | ||
6 | |||
1 | 2022-08-04 Sergei Trofimovich <slyich@gmail.com> | 7 | 2022-08-04 Sergei Trofimovich <slyich@gmail.com> |
2 | 8 | ||
3 | * low_high_pc.c (handle_die): Drop redundant 'lx' suffix. | 9 | * low_high_pc.c (handle_die): Drop redundant 'lx' suffix. |
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 | |||
73 | env DEBUGINFOD_URLS="http://127.0.0.1:"$PORT1 LD_LIBRARY_PATH=$ldpath ${abs_top_builddir}/debuginfod/debuginfod-find\ | 73 | env DEBUGINFOD_URLS="http://127.0.0.1:"$PORT1 LD_LIBRARY_PATH=$ldpath ${abs_top_builddir}/debuginfod/debuginfod-find\ |
74 | -vvv executable F/prog > vlog-find$PORT1.1 2>&1 | 74 | -vvv executable F/prog > vlog-find$PORT1.1 2>&1 |
75 | tempfiles vlog-find$PORT1.1 | 75 | tempfiles vlog-find$PORT1.1 |
76 | grep 'Content-Length: ' vlog-find$PORT1.1 | 76 | errfiles vlog-find$PORT1.1 |
77 | grep 'X-DEBUGINFOD-FILE: ' vlog-find$PORT1.1 | 77 | cat vlog-find$PORT1.1 |
78 | grep 'X-DEBUGINFOD-SIZE: ' vlog-find$PORT1.1 | 78 | grep 'Headers:' vlog-find$PORT1.1 |
79 | grep 'X-DEBUGINFOD-FILE: prog' vlog-find$PORT1.1 | ||
80 | grep 'X-DEBUGINFOD-SIZE: ' vlog-find$PORT1.1 | ||
79 | 81 | ||
80 | # Check to see if an executable file located in an archive prints the file's description and archive | 82 | # Check to see if an executable file located in an archive prints the file's description and archive |
81 | env DEBUGINFOD_URLS="http://127.0.0.1:"$PORT1 LD_LIBRARY_PATH=$ldpath ${abs_top_builddir}/debuginfod/debuginfod-find\ | 83 | env DEBUGINFOD_URLS="http://127.0.0.1:"$PORT1 LD_LIBRARY_PATH=$ldpath ${abs_top_builddir}/debuginfod/debuginfod-find\ |
82 | -vvv executable c36708a78618d597dee15d0dc989f093ca5f9120 > vlog-find$PORT1.2 2>&1 | 84 | -vvv executable c36708a78618d597dee15d0dc989f093ca5f9120 > vlog-find$PORT1.2 2>&1 |
83 | tempfiles vlog-find$PORT1.2 | 85 | tempfiles vlog-find$PORT1.2 |
84 | grep 'Content-Length: ' vlog-find$PORT1.2 | 86 | errfiles vlog-find$PORT1.2 |
85 | grep 'X-DEBUGINFOD-FILE: ' vlog-find$PORT1.2 | 87 | cat vlog-find$PORT1.2 |
86 | grep 'X-DEBUGINFOD-SIZE: ' vlog-find$PORT1.2 | 88 | grep 'Headers:' vlog-find$PORT1.2 |
89 | grep 'X-DEBUGINFOD-FILE: ' vlog-find$PORT1.2 | ||
90 | grep 'X-DEBUGINFOD-SIZE: ' vlog-find$PORT1.2 | ||
87 | grep 'X-DEBUGINFOD-ARCHIVE: ' vlog-find$PORT1.2 | 91 | grep 'X-DEBUGINFOD-ARCHIVE: ' vlog-find$PORT1.2 |
88 | 92 | ||
89 | # Check that X-DEBUGINFOD-SIZE matches the size of each file | 93 | # Check that X-DEBUGINFOD-SIZE matches the size of each file |
@@ -94,6 +98,38 @@ do | |||
94 | test $st_size -eq $x_debuginfod_size | 98 | test $st_size -eq $x_debuginfod_size |
95 | done | 99 | done |
96 | 100 | ||
101 | rm -rf $DEBUGINFOD_CACHE_PATH | ||
102 | BUILDID=`env LD_LIBRARY_PATH=$ldpath ${abs_builddir}/../src/readelf \ | ||
103 | -a F/prog | grep 'Build ID' | cut -d ' ' -f 7` | ||
104 | netcat_dir="buildid/$BUILDID/" | ||
105 | mkdir -p ${PWD}/$netcat_dir | ||
106 | cp F/prog ${PWD}/$netcat_dir/executable | ||
107 | tempfiles F/prog | ||
108 | |||
109 | # Netcat dies after answering the request | ||
110 | 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" & | ||
111 | # Wait until the netcat port is in use. Otherwise debuginfod-find can query | ||
112 | # before netcat is ready. | ||
113 | SECONDS=0 | ||
114 | nc_start=$SECONDS | ||
115 | while [ ! $(lsof -i -P -n | grep LISTEN | grep "nc.*$PORT2") ] | ||
116 | do | ||
117 | # If it takes longer than 5 seconds for netcat to start up, then fail | ||
118 | duration=$(( SECONDS - nc_start )) | ||
119 | if [ $SECONDS -gt 5 ] | ||
120 | then | ||
121 | err | ||
122 | fi | ||
123 | done | ||
124 | |||
125 | env DEBUGINFOD_URLS="http://127.0.0.1:"$PORT2 LD_LIBRARY_PATH=$ldpath ${abs_top_builddir}/debuginfod/debuginfod-find\ | ||
126 | -vvv executable $BUILDID > vlog-find$PORT2 2>&1 | ||
127 | errfiles vlog-find$PORT2 | ||
128 | tempfiles vlog-find$PORT2 | ||
129 | cat vlog-find$PORT2 | grep "X-DEBUGINFOD-" | ||
130 | rm -f "$netcat_dir"executable | ||
131 | rmdir -p $netcat_dir | ||
132 | |||
97 | kill $PID1 | 133 | kill $PID1 |
98 | wait $PID1 | 134 | wait $PID1 |
99 | PID1=0 | 135 | PID1=0 |