[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