[llvm] 32a02a9 - [Debuginfod] DEBUGINFOD_HEADERS_FILE environment variable
Daniel Thornburgh via llvm-commits
llvm-commits at lists.llvm.org
Mon Nov 7 16:34:42 PST 2022
Author: Daniel Thornburgh
Date: 2022-11-07T16:34:37-08:00
New Revision: 32a02a9c6bad489ce7c02f3f0b306a8fc1e67fd5
URL: https://github.com/llvm/llvm-project/commit/32a02a9c6bad489ce7c02f3f0b306a8fc1e67fd5
DIFF: https://github.com/llvm/llvm-project/commit/32a02a9c6bad489ce7c02f3f0b306a8fc1e67fd5.diff
LOG: [Debuginfod] DEBUGINFOD_HEADERS_FILE environment variable
This change adds a DEBUGINFOD_HEADERS_FILE environment variable provides
a file containing HTTP headers to attach to outgoing HTTP requests, one
per line. This allows a file permissioned with OS access control
mechanisms to supply bearer credentials for Debuginfod requests.
This matches the mechanism recently added to elfutils' libdebuginfod.
Reviewed By: MaskRay
Differential Revision: https://reviews.llvm.org/D136303
Added:
llvm/test/tools/llvm-debuginfod-find/Inputs/capture_req.py
llvm/test/tools/llvm-debuginfod-find/Inputs/headers
llvm/test/tools/llvm-debuginfod-find/headers.test
Modified:
llvm/include/llvm/Debuginfod/HTTPClient.h
llvm/lib/Debuginfod/Debuginfod.cpp
llvm/lib/Debuginfod/HTTPClient.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/Debuginfod/HTTPClient.h b/llvm/include/llvm/Debuginfod/HTTPClient.h
index 6c94961032e75..1c9f719051eca 100644
--- a/llvm/include/llvm/Debuginfod/HTTPClient.h
+++ b/llvm/include/llvm/Debuginfod/HTTPClient.h
@@ -27,6 +27,7 @@ enum class HTTPMethod { GET };
/// A stateless description of an outbound HTTP request.
struct HTTPRequest {
SmallString<128> Url;
+ SmallVector<std::string, 0> Headers;
HTTPMethod Method = HTTPMethod::GET;
bool FollowRedirects = true;
HTTPRequest(StringRef Url);
diff --git a/llvm/lib/Debuginfod/Debuginfod.cpp b/llvm/lib/Debuginfod/Debuginfod.cpp
index ee5cc5141f74f..f20b5bc677e00 100644
--- a/llvm/lib/Debuginfod/Debuginfod.cpp
+++ b/llvm/lib/Debuginfod/Debuginfod.cpp
@@ -22,6 +22,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Debuginfod/Debuginfod.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/Magic.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
@@ -34,6 +35,7 @@
#include "llvm/Support/Errc.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/ThreadPool.h"
#include "llvm/Support/xxhash.h"
@@ -169,6 +171,44 @@ Error StreamedHTTPResponseHandler::handleBodyChunk(StringRef BodyChunk) {
return Error::success();
}
+// An over-accepting simplification of the HTTP RFC 7230 spec.
+static bool isHeader(StringRef S) {
+ StringRef Name;
+ StringRef Value;
+ std::tie(Name, Value) = S.split(':');
+ if (Name.empty() || Value.empty())
+ return false;
+ return all_of(Name, [](char C) { return llvm::isPrint(C) && C != ' '; }) &&
+ all_of(Value, [](char C) { return llvm::isPrint(C) || C == '\t'; });
+}
+
+static SmallVector<std::string, 0> getHeaders() {
+ const char *Filename = getenv("DEBUGINFOD_HEADERS_FILE");
+ if (!Filename)
+ return {};
+ ErrorOr<std::unique_ptr<MemoryBuffer>> HeadersFile =
+ MemoryBuffer::getFile(Filename, /*IsText=*/true);
+ if (!HeadersFile)
+ return {};
+
+ SmallVector<std::string, 0> Headers;
+ uint64_t LineNumber = 0;
+ for (StringRef Line : llvm::split((*HeadersFile)->getBuffer(), '\n')) {
+ LineNumber++;
+ if (!isHeader(Line)) {
+ if (!all_of(Line, llvm::isSpace))
+ WithColor::warning()
+ << "could not parse debuginfod header: " << Filename << ':'
+ << LineNumber << '\n';
+ continue;
+ }
+ if (Line.back() == '\r')
+ Line = Line.drop_back();
+ Headers.emplace_back(Line);
+ }
+ return Headers;
+}
+
Expected<std::string> getCachedOrDownloadArtifact(
StringRef UniqueKey, StringRef UrlPath, StringRef CacheDirectoryPath,
ArrayRef<StringRef> DebuginfodUrls, std::chrono::milliseconds Timeout) {
@@ -214,6 +254,7 @@ Expected<std::string> getCachedOrDownloadArtifact(
StreamedHTTPResponseHandler Handler([&]() { return CacheAddStream(Task); },
Client);
HTTPRequest Request(ArtifactUrl);
+ Request.Headers = getHeaders();
Error Err = Client.perform(Request, Handler);
if (Err)
return std::move(Err);
diff --git a/llvm/lib/Debuginfod/HTTPClient.cpp b/llvm/lib/Debuginfod/HTTPClient.cpp
index 3376eaa7cd0d2..f9201e4f96268 100644
--- a/llvm/lib/Debuginfod/HTTPClient.cpp
+++ b/llvm/lib/Debuginfod/HTTPClient.cpp
@@ -111,9 +111,15 @@ Error HTTPClient::perform(const HTTPRequest &Request,
curl_easy_setopt(Curl, CURLOPT_URL, Url.c_str());
curl_easy_setopt(Curl, CURLOPT_FOLLOWLOCATION, Request.FollowRedirects);
+ curl_slist *Headers = nullptr;
+ for (const std::string &Header : Request.Headers)
+ Headers = curl_slist_append(Headers, Header.c_str());
+ curl_easy_setopt(Curl, CURLOPT_HTTPHEADER, Headers);
+
CurlHTTPRequest CurlRequest(Handler);
curl_easy_setopt(Curl, CURLOPT_WRITEDATA, &CurlRequest);
CURLcode CurlRes = curl_easy_perform(Curl);
+ curl_slist_free_all(Headers);
if (CurlRes != CURLE_OK)
return joinErrors(std::move(CurlRequest.ErrorState),
createStringError(errc::io_error,
diff --git a/llvm/test/tools/llvm-debuginfod-find/Inputs/capture_req.py b/llvm/test/tools/llvm-debuginfod-find/Inputs/capture_req.py
new file mode 100644
index 0000000000000..56fa2d08a0897
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfod-find/Inputs/capture_req.py
@@ -0,0 +1,23 @@
+import http.server
+import os
+import subprocess
+import sys
+import threading
+
+class TrivialHandler(http.server.BaseHTTPRequestHandler):
+ def do_GET(self):
+ self.send_response(501)
+
+ def log_request(self, *args, **kwargs):
+ print(self.requestline)
+ print(self.headers)
+
+httpd = http.server.HTTPServer(('', 0), TrivialHandler)
+port = httpd.socket.getsockname()[1]
+
+try:
+ t = threading.Thread(target=httpd.serve_forever).start()
+ os.environ['DEBUGINFOD_URLS'] =f'http://localhost:{port}'
+ subprocess.run(sys.argv[1:], capture_output = True)
+finally:
+ httpd.shutdown()
diff --git a/llvm/test/tools/llvm-debuginfod-find/Inputs/headers b/llvm/test/tools/llvm-debuginfod-find/Inputs/headers
new file mode 100644
index 0000000000000..9f66ac2821c09
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfod-find/Inputs/headers
@@ -0,0 +1,12 @@
+
+
+A:
+:A
+:
+A :B
+
+A:B
+C: D
+E:F
+hi!$: j k
+
diff --git a/llvm/test/tools/llvm-debuginfod-find/headers.test b/llvm/test/tools/llvm-debuginfod-find/headers.test
new file mode 100644
index 0000000000000..6fe814db51799
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfod-find/headers.test
@@ -0,0 +1,27 @@
+REQUIRES: curl
+
+RUN: %python %S/Inputs/capture_req.py llvm-debuginfod-find --debuginfo 0 \
+RUN: | FileCheck --check-prefix NO-HEADERS %s
+RUN: DEBUGINFOD_HEADERS_FILE=bad %python %S/Inputs/capture_req.py \
+RUN: llvm-debuginfod-find --debuginfo 0 \
+RUN: | FileCheck --check-prefix NO-HEADERS %s
+RUN: DEBUGINFOD_HEADERS_FILE=%S/Inputs/headers %python %S/Inputs/capture_req.py \
+RUN: llvm-debuginfod-find --debuginfo 0 \
+RUN: | FileCheck --check-prefix HEADERS %s
+RUN: DEBUGINFOD_HEADERS_FILE=%S/Inputs/headers DEBUGINFOD_URLS=fake not llvm-debuginfod-find --debuginfo 0 2>&1 \
+RUN: | FileCheck --check-prefix ERR -DHEADER_FILE=%S/Inputs/headers %s
+
+NO-HEADERS: Accept: */*
+NO-HEADERS-NOT: {{.}}
+
+HEADERS: Accept: */*
+HEADERS-NEXT: A: B
+HEADERS-NEXT: C: D
+HEADERS-NEXT: E: F
+HEADERS-NEXT: hi!$: j k
+HEADERS-NOT: {{.}}
+
+ERR: warning: could not parse debuginfod header: [[HEADER_FILE]]:3
+ERR-NEXT: warning: could not parse debuginfod header: [[HEADER_FILE]]:4
+ERR-NEXT: warning: could not parse debuginfod header: [[HEADER_FILE]]:5
+ERR-NEXT: warning: could not parse debuginfod header: [[HEADER_FILE]]:6
More information about the llvm-commits
mailing list