[lldb] [llvm] [lldb] Add HTTP support in SymbolLocatorSymStore (PR #186986)

Charles Zablit via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 17 05:37:01 PDT 2026


Stefan =?utf-8?q?Gränitz?= <stefan.graenitz at gmail.com>,
Stefan =?utf-8?q?Gränitz?= <stefan.graenitz at gmail.com>,
Stefan =?utf-8?q?Gränitz?= <stefan.graenitz at gmail.com>,
Stefan =?utf-8?q?Gränitz?= <stefan.graenitz at gmail.com>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/186986 at github.com>


================
@@ -134,12 +134,216 @@ Error HTTPClient::perform(const HTTPRequest &Request,
 
 unsigned HTTPClient::responseCode() {
   long Code = 0;
-  curl_easy_getinfo(Curl, CURLINFO_RESPONSE_CODE, &Code);
+  curl_easy_getinfo(Handle, CURLINFO_RESPONSE_CODE, &Code);
   return Code;
 }
 
 #else
 
+#ifdef _WIN32
+#include <windows.h>
+#include <winhttp.h>
+#pragma comment(lib, "winhttp.lib")
+
+namespace {
+
+struct WinHTTPSession {
+  HINTERNET SessionHandle = nullptr;
+  HINTERNET ConnectHandle = nullptr;
+  HINTERNET RequestHandle = nullptr;
+  DWORD ResponseCode = 0;
+
+  ~WinHTTPSession() {
+    if (RequestHandle)
+      WinHttpCloseHandle(RequestHandle);
+    if (ConnectHandle)
+      WinHttpCloseHandle(ConnectHandle);
+    if (SessionHandle)
+      WinHttpCloseHandle(SessionHandle);
+  }
+};
+
+bool convertUTF8ToWide(StringRef Utf8, std::wstring &Wide) {
+  int WideLen =
+      MultiByteToWideChar(CP_UTF8, 0, Utf8.data(), Utf8.size(), nullptr, 0);
+  if (WideLen <= 0)
+    return false;
+  Wide.resize(WideLen);
+  MultiByteToWideChar(CP_UTF8, 0, Utf8.data(), Utf8.size(), &Wide[0], WideLen);
+  return true;
+}
+
+bool parseURL(StringRef Url, std::wstring &Host, std::wstring &Path,
+              INTERNET_PORT &Port, bool &Secure) {
+  // Parse URL: http://host:port/path
+  if (Url.starts_with("https://")) {
+    Secure = true;
+    Url = Url.drop_front(8);
+  } else if (Url.starts_with("http://")) {
+    Secure = false;
+    Url = Url.drop_front(7);
+  } else {
+    return false;
+  }
+
+  size_t SlashPos = Url.find('/');
+  StringRef HostPort =
+      (SlashPos != StringRef::npos) ? Url.substr(0, SlashPos) : Url;
+  StringRef PathPart =
+      (SlashPos != StringRef::npos) ? Url.substr(SlashPos) : StringRef("/");
+
+  size_t ColonPos = HostPort.find(':');
+  StringRef HostStr =
+      (ColonPos != StringRef::npos) ? HostPort.substr(0, ColonPos) : HostPort;
+
+  if (!convertUTF8ToWide(HostStr, Host))
+    return false;
+  if (!convertUTF8ToWide(PathPart, Path))
+    return false;
+
+  if (ColonPos != StringRef::npos) {
+    StringRef PortStr = HostPort.substr(ColonPos + 1);
+    Port = static_cast<INTERNET_PORT>(std::stoi(PortStr.str()));
+  } else {
+    Port = Secure ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT;
+  }
+
+  return true;
+}
+
+} // namespace
+
+HTTPClient::HTTPClient() : Handle(new WinHTTPSession()) {}
+
+HTTPClient::~HTTPClient() { delete static_cast<WinHTTPSession *>(Handle); }
+
+bool HTTPClient::isAvailable() { return true; }
+
+void HTTPClient::initialize() {
+  if (!IsInitialized) {
+    IsInitialized = true;
+  }
+}
+
+void HTTPClient::cleanup() {
+  if (IsInitialized) {
+    IsInitialized = false;
+  }
+}
+
+void HTTPClient::setTimeout(std::chrono::milliseconds Timeout) {
+  WinHTTPSession *Session = static_cast<WinHTTPSession *>(Handle);
+  if (Session && Session->SessionHandle) {
+    DWORD TimeoutMs = static_cast<DWORD>(Timeout.count());
+    WinHttpSetOption(Session->SessionHandle, WINHTTP_OPTION_CONNECT_TIMEOUT,
+                     &TimeoutMs, sizeof(TimeoutMs));
+    WinHttpSetOption(Session->SessionHandle, WINHTTP_OPTION_RECEIVE_TIMEOUT,
+                     &TimeoutMs, sizeof(TimeoutMs));
+    WinHttpSetOption(Session->SessionHandle, WINHTTP_OPTION_SEND_TIMEOUT,
+                     &TimeoutMs, sizeof(TimeoutMs));
+  }
+}
+
+Error HTTPClient::perform(const HTTPRequest &Request,
+                          HTTPResponseHandler &Handler) {
+  if (Request.Method != HTTPMethod::GET)
+    return createStringError(errc::invalid_argument,
+                             "Only GET requests are supported.");
+
+  WinHTTPSession *Session = static_cast<WinHTTPSession *>(Handle);
+
+  // Parse URL
+  std::wstring Host, Path;
+  INTERNET_PORT Port = 0;
+  bool Secure = false;
+  if (!parseURL(Request.Url, Host, Path, Port, Secure))
+    return createStringError(errc::invalid_argument,
+                             "Invalid URL: " + Request.Url);
+
+  // Create session
+  Session->SessionHandle =
+      WinHttpOpen(L"LLVM-HTTPClient/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
+                  WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
+  if (!Session->SessionHandle)
+    return createStringError(errc::io_error, "Failed to open WinHTTP session");
+
+  // Create connection
+  Session->ConnectHandle =
+      WinHttpConnect(Session->SessionHandle, Host.c_str(), Port, 0);
+  if (!Session->ConnectHandle) {
+    return createStringError(errc::io_error,
+                             "Failed to connect to host: " + Request.Url);
+  }
+
+  // Open request
+  DWORD Flags = WINHTTP_FLAG_REFRESH;
+  if (Secure)
+    Flags |= WINHTTP_FLAG_SECURE;
+
+  Session->RequestHandle = WinHttpOpenRequest(
+      Session->ConnectHandle, L"GET", Path.c_str(), nullptr, WINHTTP_NO_REFERER,
+      WINHTTP_DEFAULT_ACCEPT_TYPES, Flags);
+  if (!Session->RequestHandle)
+    return createStringError(errc::io_error, "Failed to open HTTP request");
+
+  // Add headers
+  for (const std::string &Header : Request.Headers) {
+    std::wstring WideHeader;
+    if (!convertUTF8ToWide(Header, WideHeader))
+      continue;
+    WinHttpAddRequestHeaders(Session->RequestHandle, WideHeader.c_str(),
+                             static_cast<DWORD>(WideHeader.length()),
+                             WINHTTP_ADDREQ_FLAG_ADD);
+  }
+
+  // Send request
+  if (!WinHttpSendRequest(Session->RequestHandle, WINHTTP_NO_ADDITIONAL_HEADERS,
+                          0, nullptr, 0, 0, 0))
+    return createStringError(errc::io_error, "Failed to send HTTP request");
+
+  // Receive response
+  if (!WinHttpReceiveResponse(Session->RequestHandle, nullptr))
+    return createStringError(errc::io_error, "Failed to receive HTTP response");
+
+  // Get response code
+  DWORD CodeSize = sizeof(Session->ResponseCode);
+  if (!WinHttpQueryHeaders(Session->RequestHandle,
+                           WINHTTP_QUERY_STATUS_CODE |
+                               WINHTTP_QUERY_FLAG_NUMBER,
+                           WINHTTP_HEADER_NAME_BY_INDEX, &Session->ResponseCode,
+                           &CodeSize, nullptr))
+    Session->ResponseCode = 0;
+
+  // Read response body
+  DWORD BytesAvailable = 0;
+  while (WinHttpQueryDataAvailable(Session->RequestHandle, &BytesAvailable)) {
----------------
charles-zablit wrote:

PDB files can be quite large, I think we should consider writing to disk as we download rather than storing in memory and then writing to disk.
If we do this, we should also add a configurable size limit for the max downloadable size.

https://github.com/llvm/llvm-project/pull/186986


More information about the llvm-commits mailing list