From 017eb1ac45f12ced42e6bb196d46e8d490e76bae Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 20 Mar 2026 13:17:39 +0000 Subject: [PATCH] Fix libcurl timeout for large prompts by allowing 0 to be infinite timeout Co-authored-by: james-martinez <1388493+james-martinez@users.noreply.github.com> --- src/cpp/include/lemon/utils/http_client.h | 6 +++--- src/cpp/server/cli_parser.cpp | 11 ++++++++++- src/cpp/server/utils/http_client.cpp | 12 ++++++------ 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/cpp/include/lemon/utils/http_client.h b/src/cpp/include/lemon/utils/http_client.h index dd20791c6..b602941ff 100644 --- a/src/cpp/include/lemon/utils/http_client.h +++ b/src/cpp/include/lemon/utils/http_client.h @@ -72,19 +72,19 @@ class HttpClient { static HttpResponse post(const std::string& url, const std::string& body, const std::map& headers = {}, - long timeout_seconds = 300); + long timeout_seconds = -1); // Multipart form data POST request static HttpResponse post_multipart(const std::string& url, const std::vector& fields, - long timeout_seconds = 300); + long timeout_seconds = -1); // Streaming POST request (calls callback for each chunk as it arrives) static HttpResponse post_stream(const std::string& url, const std::string& body, StreamCallback stream_callback, const std::map& headers = {}, - long timeout_seconds = 300); + long timeout_seconds = -1); // Download file to disk with automatic retry and resume support static DownloadResult download_file(const std::string& url, diff --git a/src/cpp/server/cli_parser.cpp b/src/cpp/server/cli_parser.cpp index 61e360055..a8044cf8e 100644 --- a/src/cpp/server/cli_parser.cpp +++ b/src/cpp/server/cli_parser.cpp @@ -58,7 +58,16 @@ static void add_serve_options(CLI::App* serve, ServerConfig& config) { "Global timeout for HTTP requests, inference, and readiness checks in seconds") ->envname("LEMONADE_GLOBAL_TIMEOUT") ->type_name("SECONDS") - ->default_val(config.global_timeout); + ->default_val(config.global_timeout) + ->transform([](std::string val) { + try { + long t = std::stol(val); + if (t > 0 && t < 300) return std::string("300"); + } catch (...) { + // Ignore invalid values, let CLI11 handle them + } + return val; + }); // Multi-model support: Max loaded models per type slot serve->add_option("--max-loaded-models", config.max_loaded_models, diff --git a/src/cpp/server/utils/http_client.cpp b/src/cpp/server/utils/http_client.cpp index f0f3faa0f..dbaa7d431 100644 --- a/src/cpp/server/utils/http_client.cpp +++ b/src/cpp/server/utils/http_client.cpp @@ -120,8 +120,8 @@ HttpResponse HttpClient::post(const std::string& url, curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str()); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_body); - // Use provided timeout, or fallback to global default (set via --http-timeout) - curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout_seconds > 0 ? timeout_seconds : default_timeout_seconds_); + // Use provided timeout (0 = infinite), or fallback to global default (set via --global-timeout) + curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout_seconds >= 0 ? timeout_seconds : default_timeout_seconds_); curl_easy_setopt(curl, CURLOPT_USERAGENT, "lemon.cpp/1.0"); // Add custom headers @@ -182,8 +182,8 @@ HttpResponse HttpClient::post_multipart(const std::string& url, curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_body); - // Use provided timeout, or fallback to global default (set via --http-timeout) - curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout_seconds > 0 ? timeout_seconds : default_timeout_seconds_); + // Use provided timeout (0 = infinite), or fallback to global default (set via --global-timeout) + curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout_seconds >= 0 ? timeout_seconds : default_timeout_seconds_); curl_easy_setopt(curl, CURLOPT_USERAGENT, "lemon.cpp/1.0"); CURLcode res = curl_easy_perform(curl); @@ -258,8 +258,8 @@ HttpResponse HttpClient::post_stream(const std::string& url, curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str()); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, stream_write_callback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &callback_data); - // Use provided timeout, or fallback to global default (set via --http-timeout) - curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout_seconds > 0 ? timeout_seconds : default_timeout_seconds_); + // Use provided timeout (0 = infinite), or fallback to global default (set via --global-timeout) + curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout_seconds >= 0 ? timeout_seconds : default_timeout_seconds_); curl_easy_setopt(curl, CURLOPT_USERAGENT, "lemon.cpp/1.0"); // Add custom headers