Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions sdk_v2/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ set(FOUNDRY_LOCAL_SOURCES
src/exception.cc
src/inferencing/generative/genai_config.cc
src/http/http_client.cc
src/http/curl_transport.cc
src/inferencing/generative/genai_model_instance.cc
src/inferencing/generative/tokenizer.cc
src/logger.cc
Expand Down
11 changes: 7 additions & 4 deletions sdk_v2/cpp/src/download/blob_downloader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
// does not honor SSL_CERT_FILE. On non-Windows builds we install a CurlTransport preconfigured with
// CAInfo (see MakeBlobClientOptions below). Desktop Windows uses the default WinHTTP transport.
#if !defined(FOUNDRY_LOCAL_USE_WINHTTP_TRANSPORT)
#include "http/curl_transport.h"

#include <azure/core/http/curl_transport.hpp>
#endif

Expand All @@ -50,10 +52,11 @@ constexpr size_t kStreamingBufferBytes = 64 * 1024;
Azure::Storage::Blobs::BlobClientOptions MakeBlobClientOptions() {
Azure::Storage::Blobs::BlobClientOptions options;
#if !defined(FOUNDRY_LOCAL_USE_WINHTTP_TRANSPORT)
if (std::string ca_bundle = fl::http::CaBundleFile(); !ca_bundle.empty()) {
Azure::Core::Http::CurlTransportOptions curl_opts;
curl_opts.CAInfo = std::move(ca_bundle);
options.Transport.Transport = std::make_shared<Azure::Core::Http::CurlTransport>(curl_opts);
// Only override the Storage SDK's default transport when a CA bundle is configured; the options are
// cached and shared with our other curl transports (see http/curl_transport.h).
if (!fl::http::CaBundleFile().empty()) {
options.Transport.Transport =
std::make_shared<Azure::Core::Http::CurlTransport>(fl::http::CachedCurlTransportOptions());
}
#endif
return options;
Expand Down
29 changes: 29 additions & 0 deletions sdk_v2/cpp/src/http/curl_transport.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "http/curl_transport.h"

#if !defined(FOUNDRY_LOCAL_USE_WINHTTP_TRANSPORT)

#include "http/http_client.h"

#include <string>
#include <utility>

namespace fl {
namespace http {

const Azure::Core::Http::CurlTransportOptions& CachedCurlTransportOptions() {
static const Azure::Core::Http::CurlTransportOptions options = [] {
Azure::Core::Http::CurlTransportOptions opts;
if (const std::string& ca_bundle = CaBundleFile(); !ca_bundle.empty()) {
opts.CAInfo = ca_bundle;
Comment thread
skottmckay marked this conversation as resolved.
Outdated
}
return opts;
}();
return options;
}

} // namespace http
} // namespace fl

#endif // !FOUNDRY_LOCAL_USE_WINHTTP_TRANSPORT
25 changes: 25 additions & 0 deletions sdk_v2/cpp/src/http/curl_transport.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once

// Desktop Windows uses the WinHTTP transport and never links libcurl, so the curl transport options
// are only meaningful for the non-WinHTTP (libcurl) builds. Guard the whole header accordingly so
// includers on Windows do not pull in the Azure curl transport dependency.
#if !defined(FOUNDRY_LOCAL_USE_WINHTTP_TRANSPORT)

#include <azure/core/http/curl_transport.hpp>

namespace fl {
namespace http {

/// Returns the process-wide libcurl transport options, with `CAInfo` populated from `SSL_CERT_FILE`
/// (via `CaBundleFile`). Built once and shared by every libcurl transport we construct — direct
/// requests, file downloads, and the Azure Storage blob client — because the CA bundle path is fixed
/// for the process lifetime. When `SSL_CERT_FILE` is unset, `CAInfo` is empty and libcurl falls back
/// to its compiled-in default. The returned reference is valid for the lifetime of the process.
const Azure::Core::Http::CurlTransportOptions& CachedCurlTransportOptions();

} // namespace http
} // namespace fl

#endif // !FOUNDRY_LOCAL_USE_WINHTTP_TRANSPORT
29 changes: 14 additions & 15 deletions sdk_v2/cpp/src/http/http_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@
#if defined(FOUNDRY_LOCAL_USE_WINHTTP_TRANSPORT)
#include <azure/core/http/win_http_transport.hpp>
#else
#include "http/curl_transport.h"

#include <azure/core/http/curl_transport.hpp>
#endif

#include <chrono>
#include <cstdlib>
#include <random>
#include <string>
#include <thread>
Expand All @@ -32,12 +33,14 @@
namespace fl {
namespace http {

std::string CaBundleFile() {
const char* cert_file = std::getenv("SSL_CERT_FILE");
if (cert_file != nullptr && cert_file[0] != '\0') {
return cert_file;
}
return {};
const std::string& CaBundleFile() {
// SSL_CERT_FILE is fixed for the process lifetime (callers set it before loading the library), so
// read it once and return a reference to the cached path for every request.
static const std::string ca_bundle = [] {
auto cert_file = Utils::GetEnv("SSL_CERT_FILE");
return (cert_file && !cert_file->empty()) ? std::move(*cert_file) : std::string();
}();
Comment thread
skottmckay marked this conversation as resolved.
return ca_bundle;
}

namespace {
Expand All @@ -58,14 +61,10 @@ HttpRawResult HttpRequestRaw(const Azure::Core::Http::HttpMethod& method,
#if defined(FOUNDRY_LOCAL_USE_WINHTTP_TRANSPORT)
WinHttpTransport transport;
#else
// The bundled libcurl does not honor the SSL_CERT_FILE environment variable (it was built with a
// compiled-in default CA path that does not exist on platforms like Android). Explicitly pass the
// CA bundle via CAInfo so the caller-provided trust store is actually used for TLS verification.
CurlTransportOptions curl_opts;
if (std::string ca_bundle = CaBundleFile(); !ca_bundle.empty()) {
curl_opts.CAInfo = std::move(ca_bundle);
}
CurlTransport transport(curl_opts);
// libcurl does not honor SSL_CERT_FILE (its compiled-in default CA path is absent on Android), so
// we pass the CA bundle explicitly via CAInfo. The options are cached and shared (see
// http/curl_transport.h) and copied into the per-request transport.
CurlTransport transport(CachedCurlTransportOptions());
#endif

// Build the request. For methods with a body (POST), attach a MemoryBodyStream.
Expand Down
13 changes: 7 additions & 6 deletions sdk_v2/cpp/src/http/http_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,13 @@ struct HttpRequestOptions {
};

/// Returns the CA bundle file path from the `SSL_CERT_FILE` environment variable, or an empty
/// string when it is unset/empty. The bundled libcurl does not consult `SSL_CERT_FILE`
/// automatically (it was built with a compiled-in default CA path that does not exist on platforms
/// like Android), so every libcurl-based transport we construct — direct requests, file downloads,
/// and the Azure Storage blob client — must pass this explicitly as `CAInfo`. On desktop Windows the
/// WinHTTP transport uses the OS trust store and ignores this.
std::string CaBundleFile();
/// string when it is unset/empty. The value is read once and cached for the process lifetime, so a
/// reference to the cached string is returned (valid until process exit). The bundled libcurl does
/// not consult `SSL_CERT_FILE` automatically (it was built with a compiled-in default CA path that
/// does not exist on platforms like Android), so every libcurl-based transport we construct — direct
/// requests, file downloads, and the Azure Storage blob client — must pass this explicitly as
/// `CAInfo`. On desktop Windows the WinHTTP transport uses the OS trust store and ignores this.
const std::string& CaBundleFile();

/// Perform an HTTP POST and return status, headers, and body without throwing on non-2xx responses.
/// Transport failures are returned as `status == 0` with the error message in `body`.
Expand Down
13 changes: 5 additions & 8 deletions sdk_v2/cpp/src/http/http_download.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#if defined(FOUNDRY_LOCAL_USE_WINHTTP_TRANSPORT)
#include <azure/core/http/win_http_transport.hpp>
#else
#include "http/curl_transport.h"

#include <azure/core/http/curl_transport.hpp>
#endif

Expand Down Expand Up @@ -43,14 +45,9 @@ bool HttpDownloadFile(const std::string& url,
#if defined(FOUNDRY_LOCAL_USE_WINHTTP_TRANSPORT)
WinHttpTransport transport;
#else
// The bundled libcurl does not honor the SSL_CERT_FILE environment variable (it was built with a
// compiled-in default CA path that does not exist on platforms like Android). Explicitly pass the
// CA bundle via CAInfo so the caller-provided trust store is actually used for TLS verification.
CurlTransportOptions curl_opts;
if (std::string ca_bundle = http::CaBundleFile(); !ca_bundle.empty()) {
curl_opts.CAInfo = std::move(ca_bundle);
}
CurlTransport transport(curl_opts);
// libcurl does not honor SSL_CERT_FILE (its compiled-in default CA path is absent on Android), so
// pass the shared CA bundle explicitly via CAInfo (see http/curl_transport.h).
CurlTransport transport(http::CachedCurlTransportOptions());
#endif
Request request(HttpMethod::Get, Url(url));
request.SetHeader("User-Agent", user_agent);
Expand Down