From 67864a1273b6201b5e0f7426cfb0b8ced4460a55 Mon Sep 17 00:00:00 2001
From: Petr Shumilov
Date: Thu, 26 Mar 2026 20:48:21 +0300
Subject: [PATCH 1/3] Fix curl_multi_strerror semantics
Signed-off-by: Petr Shumilov
---
.../stdlib/curl/curl-multi-functions.h | 55 +++++++++++++++----
runtime-light/stdlib/curl/defs.h | 5 ++
2 files changed, 50 insertions(+), 10 deletions(-)
diff --git a/runtime-light/stdlib/curl/curl-multi-functions.h b/runtime-light/stdlib/curl/curl-multi-functions.h
index 52098085fa..3c781c99f6 100644
--- a/runtime-light/stdlib/curl/curl-multi-functions.h
+++ b/runtime-light/stdlib/curl/curl-multi-functions.h
@@ -173,18 +173,53 @@ inline auto f$curl_multi_close(kphp::web::curl::multi_type multi_id) noexcept ->
co_return;
}
-inline auto f$curl_multi_strerror(kphp::web::curl::multi_type multi_id) noexcept -> Optional {
- auto& curl_state{CurlInstanceState::get()};
- if (!curl_state.multi_ctx.has(multi_id)) [[unlikely]] {
- return {};
+inline auto f$curl_multi_strerror(int64_t error_num) noexcept -> Optional {
+ switch (static_cast(error_num)) {
+ case kphp::web::curl::CURLME::CALL_MULTI_PERFORM: {
+ return string{"Please call curl_multi_perform() soon"};
}
- auto& multi_ctx{curl_state.multi_ctx.get_or_init(multi_id)};
- if (multi_ctx.error_code != static_cast(kphp::web::curl::CURLME::OK)) [[likely]] {
- const auto* const desc_data{reinterpret_cast(multi_ctx.error_description.data())};
- const auto desc_size{static_cast(multi_ctx.error_description.size())};
- return string{desc_data, desc_size};
+ case kphp::web::curl::CURLME::OK: {
+ return string{"No error"};
+ }
+ case kphp::web::curl::CURLME::BAD_HANDLE: {
+ return string{"Invalid multi handle"};
+ }
+ case kphp::web::curl::CURLME::BAD_EASY_HANDLE: {
+ return string{"Invalid easy handle"};
+ }
+ case kphp::web::curl::CURLME::OUT_OF_MEMORY: {
+ return string{"Out of memory"};
+ }
+ case kphp::web::curl::CURLME::INTERNAL_ERROR: {
+ return string{"Internal error"};
+ }
+ case kphp::web::curl::CURLME::BAD_SOCKET: {
+ return string{"Invalid socket argument"};
+ }
+ case kphp::web::curl::CURLME::UNKNOWN_OPTION: {
+ return string{"Unknown option"};
+ }
+ case kphp::web::curl::CURLME::ADDED_ALREADY: {
+ return string{"The easy handle is already added to a multi handle"};
+ }
+ case kphp::web::curl::CURLME::RECURSIVE_API_CALL: {
+ return string{"API function called from within callback"};
+ }
+ case kphp::web::curl::CURLME::WAKEUP_FAILURE: {
+ return string{"Wakeup is unavailable or failed"};
+ }
+ case kphp::web::curl::CURLME::BAD_FUNCTION_ARGUMENT: {
+ return string{"A libcurl function was given a bad argument"};
+ }
+ case kphp::web::curl::CURLME::ABORTED_BY_CALLBACK: {
+ return string{"Operation was aborted by an application callback"};
+ }
+ case kphp::web::curl::CURLME::UNRECOVERABLE_POLL: {
+ return string{"Unrecoverable error in select/poll"};
+ }
+ default:
+ return {};
}
- return {};
}
inline auto f$curl_multi_errno(kphp::web::curl::multi_type multi_id) noexcept -> Optional {
diff --git a/runtime-light/stdlib/curl/defs.h b/runtime-light/stdlib/curl/defs.h
index 93688c9d61..e2ac515867 100644
--- a/runtime-light/stdlib/curl/defs.h
+++ b/runtime-light/stdlib/curl/defs.h
@@ -259,6 +259,11 @@ enum class CURLME : int16_t {
BAD_SOCKET = 5,
UNKNOWN_OPTION = 6,
ADDED_ALREADY = 7,
+ RECURSIVE_API_CALL = 8,
+ WAKEUP_FAILURE = 9,
+ BAD_FUNCTION_ARGUMENT = 10,
+ ABORTED_BY_CALLBACK = 11,
+ UNRECOVERABLE_POLL = 12,
};
enum class CURMLOPT : uint64_t {
From a9e67cd2e24a45fe5b76f0c4aed073ff5b1e7927 Mon Sep 17 00:00:00 2001
From: Petr Shumilov
Date: Thu, 26 Mar 2026 20:48:48 +0300
Subject: [PATCH 2/3] Add test
Signed-off-by: Petr Shumilov
---
tests/phpt/curl/11_curl_multi_error.php | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/tests/phpt/curl/11_curl_multi_error.php b/tests/phpt/curl/11_curl_multi_error.php
index b36a4e1cf1..72f6a754ea 100644
--- a/tests/phpt/curl/11_curl_multi_error.php
+++ b/tests/phpt/curl/11_curl_multi_error.php
@@ -3,7 +3,9 @@
function test_no_error() {
$mh = curl_multi_init();
- var_dump(curl_multi_errno($mh));
+ $errno = curl_multi_errno($mh);
+ var_dump($errno);
+ var_dump(curl_multi_strerror($errno));
curl_multi_close($mh);
}
From c3fdc032eb0411c5850167188c6c5f6f8cc91cd5 Mon Sep 17 00:00:00 2001
From: Petr Shumilov
Date: Thu, 26 Mar 2026 22:04:11 +0300
Subject: [PATCH 3/3] Move literals into image state
Signed-off-by: Petr Shumilov
---
runtime-light/state/image-state.h | 2 +
.../stdlib/curl/curl-multi-functions.h | 84 ++++++++-----------
runtime-light/stdlib/curl/curl-state.cpp | 5 ++
runtime-light/stdlib/curl/curl-state.h | 53 ++++++++++++
runtime-light/stdlib/curl/defs.h | 20 +++++
5 files changed, 115 insertions(+), 49 deletions(-)
diff --git a/runtime-light/state/image-state.h b/runtime-light/state/image-state.h
index 389316405d..2304ee059d 100644
--- a/runtime-light/state/image-state.h
+++ b/runtime-light/state/image-state.h
@@ -18,6 +18,7 @@
#include "runtime-light/allocator/allocator-state.h"
#include "runtime-light/core/reference-counter/reference-counter-functions.h"
#include "runtime-light/k2-platform/k2-api.h"
+#include "runtime-light/stdlib/curl/curl-state.h"
#include "runtime-light/stdlib/diagnostics/logs.h"
#include "runtime-light/stdlib/file/file-system-state.h"
#include "runtime-light/stdlib/math/math-state.h"
@@ -46,6 +47,7 @@ struct ImageState final : private vk::not_copyable {
TimeImageState time_image_state;
MathImageState math_image_state;
RpcImageState rpc_image_state;
+ CurlImageState curl_image_state;
ImageState() noexcept {
if (const int64_t sysconf_max_buffer_size{k2::sysconf(_SC_GETPW_R_SIZE_MAX)}; sysconf_max_buffer_size != -1) {
diff --git a/runtime-light/stdlib/curl/curl-multi-functions.h b/runtime-light/stdlib/curl/curl-multi-functions.h
index 3c781c99f6..c14552a36e 100644
--- a/runtime-light/stdlib/curl/curl-multi-functions.h
+++ b/runtime-light/stdlib/curl/curl-multi-functions.h
@@ -46,7 +46,7 @@ inline auto f$curl_multi_add_handle(kphp::web::curl::multi_type multi_id, kphp::
auto res{co_await kphp::forks::id_managed(kphp::web::composite_transfer_add(kphp::web::composite_transfer{multi_id}, kphp::web::simple_transfer{easy_id}))};
if (!res.has_value()) [[unlikely]] {
- multi_ctx.set_errno(res.error().code, res.error().description);
+ multi_ctx.set_errno(res.error().code);
kphp::web::curl::print_error("could not add a curl easy handler into multi handle", std::move(res.error()));
co_return multi_ctx.error_code;
}
@@ -67,7 +67,7 @@ inline auto f$curl_multi_remove_handle(kphp::web::curl::multi_type multi_id,
auto res{
co_await kphp::forks::id_managed(kphp::web::composite_transfer_remove(kphp::web::composite_transfer{multi_id}, kphp::web::simple_transfer{easy_id}))};
if (!res.has_value()) [[unlikely]] {
- multi_ctx.set_errno(res.error().code, res.error().description);
+ multi_ctx.set_errno(res.error().code);
kphp::web::curl::print_error("could not remove a curl easy handler from multi handle", std::move(res.error()));
co_return multi_ctx.error_code;
}
@@ -100,7 +100,7 @@ inline auto f$curl_multi_setopt(kphp::web::curl::multi_type multi_id, int64_t op
return true;
}
default:
- multi_ctx.set_errno(kphp::web::curl::CURLME::UNKNOWN_OPTION, "a libcurl function was given an incorrect PROXYTYPE kind");
+ multi_ctx.set_errno(kphp::web::curl::CURLME::UNKNOWN_OPTION);
return false;
}
}
@@ -130,7 +130,7 @@ inline auto f$curl_multi_exec(kphp::web::curl::multi_type multi_id, int64_t& sti
auto res{co_await kphp::forks::id_managed(kphp::web::composite_transfer_perform(kphp::web::composite_transfer{multi_id}))};
auto& multi_ctx{curl_state.multi_ctx.get_or_init(multi_id)};
if (!res.has_value()) [[unlikely]] {
- multi_ctx.set_errno(res.error().code, res.error().description);
+ multi_ctx.set_errno(res.error().code);
kphp::web::curl::print_error("could not execute curl multi handle", std::move(res.error()));
co_return multi_ctx.error_code;
}
@@ -148,7 +148,7 @@ inline auto f$curl_multi_getcontent(kphp::web::curl::easy_type easy_id) noexcept
if (easy_ctx.return_transfer) {
auto res{co_await kphp::forks::id_managed(kphp::web::simple_transfer_get_response(kphp::web::simple_transfer{easy_id}))};
if (!res.has_value()) [[unlikely]] {
- easy_ctx.set_errno(res.error().code, res.error().description);
+ easy_ctx.set_errno(res.error().code);
kphp::web::curl::print_error("could not get response of curl easy handle", std::move(res.error()));
co_return false;
}
@@ -165,7 +165,7 @@ inline auto f$curl_multi_close(kphp::web::curl::multi_type multi_id) noexcept ->
auto& multi_ctx{curl_state.multi_ctx.get_or_init(multi_id)};
auto res{co_await kphp::forks::id_managed(kphp::web::composite_transfer_close(kphp::web::composite_transfer{multi_id}))};
if (!res.has_value()) [[unlikely]] {
- multi_ctx.set_errno(res.error().code, res.error().description);
+ multi_ctx.set_errno(res.error().code);
kphp::web::curl::print_error("could not close curl multi handle", std::move(res.error()));
co_return;
}
@@ -175,48 +175,34 @@ inline auto f$curl_multi_close(kphp::web::curl::multi_type multi_id) noexcept ->
inline auto f$curl_multi_strerror(int64_t error_num) noexcept -> Optional {
switch (static_cast(error_num)) {
- case kphp::web::curl::CURLME::CALL_MULTI_PERFORM: {
- return string{"Please call curl_multi_perform() soon"};
- }
- case kphp::web::curl::CURLME::OK: {
- return string{"No error"};
- }
- case kphp::web::curl::CURLME::BAD_HANDLE: {
- return string{"Invalid multi handle"};
- }
- case kphp::web::curl::CURLME::BAD_EASY_HANDLE: {
- return string{"Invalid easy handle"};
- }
- case kphp::web::curl::CURLME::OUT_OF_MEMORY: {
- return string{"Out of memory"};
- }
- case kphp::web::curl::CURLME::INTERNAL_ERROR: {
- return string{"Internal error"};
- }
- case kphp::web::curl::CURLME::BAD_SOCKET: {
- return string{"Invalid socket argument"};
- }
- case kphp::web::curl::CURLME::UNKNOWN_OPTION: {
- return string{"Unknown option"};
- }
- case kphp::web::curl::CURLME::ADDED_ALREADY: {
- return string{"The easy handle is already added to a multi handle"};
- }
- case kphp::web::curl::CURLME::RECURSIVE_API_CALL: {
- return string{"API function called from within callback"};
- }
- case kphp::web::curl::CURLME::WAKEUP_FAILURE: {
- return string{"Wakeup is unavailable or failed"};
- }
- case kphp::web::curl::CURLME::BAD_FUNCTION_ARGUMENT: {
- return string{"A libcurl function was given a bad argument"};
- }
- case kphp::web::curl::CURLME::ABORTED_BY_CALLBACK: {
- return string{"Operation was aborted by an application callback"};
- }
- case kphp::web::curl::CURLME::UNRECOVERABLE_POLL: {
- return string{"Unrecoverable error in select/poll"};
- }
+ case kphp::web::curl::CURLME::CALL_MULTI_PERFORM:
+ return CurlImageState::get().CURLME_CALL_MULTI_PERFORM;
+ case kphp::web::curl::CURLME::OK:
+ return CurlImageState::get().CURLME_OK;
+ case kphp::web::curl::CURLME::BAD_HANDLE:
+ return CurlImageState::get().CURLME_BAD_HANDLE;
+ case kphp::web::curl::CURLME::BAD_EASY_HANDLE:
+ return CurlImageState::get().CURLME_BAD_EASY_HANDLE;
+ case kphp::web::curl::CURLME::OUT_OF_MEMORY:
+ return CurlImageState::get().CURLME_OUT_OF_MEMORY;
+ case kphp::web::curl::CURLME::INTERNAL_ERROR:
+ return CurlImageState::get().CURLME_INTERNAL_ERROR;
+ case kphp::web::curl::CURLME::BAD_SOCKET:
+ return CurlImageState::get().CURLME_BAD_SOCKET;
+ case kphp::web::curl::CURLME::UNKNOWN_OPTION:
+ return CurlImageState::get().CURLME_UNKNOWN_OPTION;
+ case kphp::web::curl::CURLME::ADDED_ALREADY:
+ return CurlImageState::get().CURLME_ADDED_ALREADY;
+ case kphp::web::curl::CURLME::RECURSIVE_API_CALL:
+ return CurlImageState::get().CURLME_RECURSIVE_API_CALL;
+ case kphp::web::curl::CURLME::WAKEUP_FAILURE:
+ return CurlImageState::get().CURLME_WAKEUP_FAILURE;
+ case kphp::web::curl::CURLME::BAD_FUNCTION_ARGUMENT:
+ return CurlImageState::get().CURLME_BAD_FUNCTION_ARGUMENT;
+ case kphp::web::curl::CURLME::ABORTED_BY_CALLBACK:
+ return CurlImageState::get().CURLME_ABORTED_BY_CALLBACK;
+ case kphp::web::curl::CURLME::UNRECOVERABLE_POLL:
+ return CurlImageState::get().CURLME_UNRECOVERABLE_POLL;
default:
return {};
}
@@ -240,7 +226,7 @@ inline auto f$curl_multi_select(kphp::web::curl::multi_type multi_id, double tim
auto res{co_await kphp::forks::id_managed(kphp::web::composite_transfer_wait_updates(
kphp::web::composite_transfer{multi_id}, std::chrono::duration_cast(std::chrono::duration{timeout})))};
if (!res.has_value()) [[unlikely]] {
- multi_ctx.set_errno(res.error().code, res.error().description);
+ multi_ctx.set_errno(res.error().code);
kphp::web::curl::print_error("could not select curl multi handle", std::move(res.error()));
co_return multi_ctx.error_code;
}
diff --git a/runtime-light/stdlib/curl/curl-state.cpp b/runtime-light/stdlib/curl/curl-state.cpp
index 8472e76a1b..019d97fdc6 100644
--- a/runtime-light/stdlib/curl/curl-state.cpp
+++ b/runtime-light/stdlib/curl/curl-state.cpp
@@ -4,8 +4,13 @@
#include "runtime-light/stdlib/curl/curl-state.h"
+#include "runtime-light/state/image-state.h"
#include "runtime-light/state/instance-state.h"
CurlInstanceState& CurlInstanceState::get() noexcept {
return InstanceState::get().curl_instance_state;
}
+
+const CurlImageState& CurlImageState::get() noexcept {
+ return ImageState::get().curl_image_state;
+}
diff --git a/runtime-light/stdlib/curl/curl-state.h b/runtime-light/stdlib/curl/curl-state.h
index 2b93506482..b6a551f7e2 100644
--- a/runtime-light/stdlib/curl/curl-state.h
+++ b/runtime-light/stdlib/curl/curl-state.h
@@ -7,8 +7,10 @@
#include "common/mixin/not_copyable.h"
#include "runtime-common/core/allocator/script-allocator.h"
#include "runtime-common/core/std/containers.h"
+#include "runtime-light/core/reference-counter/reference-counter-functions.h"
#include "runtime-light/stdlib/curl/curl-context.h"
#include "runtime-light/stdlib/curl/defs.h"
+#include "runtime-light/stdlib/diagnostics/logs.h"
struct CurlInstanceState final : private vk::not_copyable {
public:
@@ -58,3 +60,54 @@ inline auto CurlInstanceState::multi_ctx::get_or_init(kphp::web::curl::multi_typ
inline auto CurlInstanceState::multi_ctx::has(kphp::web::curl::multi_type multi_id) noexcept -> bool {
return ctx.find(multi_id) != ctx.end();
}
+
+struct CurlImageState final : private vk::not_copyable {
+ string CURLME_CALL_MULTI_PERFORM{kphp::web::curl::details::CURLME_CALL_MULTI_PERFORM.data(), kphp::web::curl::details::CURLME_CALL_MULTI_PERFORM.size()};
+ string CURLME_OK{kphp::web::curl::details::CURLME_OK.data(), kphp::web::curl::details::CURLME_OK.size()};
+ string CURLME_BAD_HANDLE{kphp::web::curl::details::CURLME_BAD_HANDLE.data(), kphp::web::curl::details::CURLME_BAD_HANDLE.size()};
+ string CURLME_BAD_EASY_HANDLE{kphp::web::curl::details::CURLME_BAD_EASY_HANDLE.data(), kphp::web::curl::details::CURLME_BAD_EASY_HANDLE.size()};
+ string CURLME_OUT_OF_MEMORY{kphp::web::curl::details::CURLME_OUT_OF_MEMORY.data(), kphp::web::curl::details::CURLME_OUT_OF_MEMORY.size()};
+ string CURLME_INTERNAL_ERROR{kphp::web::curl::details::CURLME_INTERNAL_ERROR.data(), kphp::web::curl::details::CURLME_INTERNAL_ERROR.size()};
+ string CURLME_BAD_SOCKET{kphp::web::curl::details::CURLME_BAD_SOCKET.data(), kphp::web::curl::details::CURLME_BAD_SOCKET.size()};
+ string CURLME_UNKNOWN_OPTION{kphp::web::curl::details::CURLME_UNKNOWN_OPTION.data(), kphp::web::curl::details::CURLME_UNKNOWN_OPTION.size()};
+ string CURLME_ADDED_ALREADY{kphp::web::curl::details::CURLME_ADDED_ALREADY.data(), kphp::web::curl::details::CURLME_ADDED_ALREADY.size()};
+ string CURLME_RECURSIVE_API_CALL{kphp::web::curl::details::CURLME_RECURSIVE_API_CALL.data(), kphp::web::curl::details::CURLME_RECURSIVE_API_CALL.size()};
+ string CURLME_WAKEUP_FAILURE{kphp::web::curl::details::CURLME_WAKEUP_FAILURE.data(), kphp::web::curl::details::CURLME_WAKEUP_FAILURE.size()};
+ string CURLME_BAD_FUNCTION_ARGUMENT{kphp::web::curl::details::CURLME_BAD_FUNCTION_ARGUMENT.data(),
+ kphp::web::curl::details::CURLME_BAD_FUNCTION_ARGUMENT.size()};
+ string CURLME_ABORTED_BY_CALLBACK{kphp::web::curl::details::CURLME_ABORTED_BY_CALLBACK.data(), kphp::web::curl::details::CURLME_ABORTED_BY_CALLBACK.size()};
+ string CURLME_UNRECOVERABLE_POLL{kphp::web::curl::details::CURLME_UNRECOVERABLE_POLL.data(), kphp::web::curl::details::CURLME_UNRECOVERABLE_POLL.size()};
+
+ CurlImageState() noexcept {
+ kphp::log::assertion((kphp::core::set_reference_counter_recursive(CURLME_CALL_MULTI_PERFORM, ExtraRefCnt::for_global_const),
+ kphp::core::is_reference_counter_recursive(CURLME_CALL_MULTI_PERFORM, ExtraRefCnt::for_global_const)));
+ kphp::log::assertion((kphp::core::set_reference_counter_recursive(CURLME_OK, ExtraRefCnt::for_global_const),
+ kphp::core::is_reference_counter_recursive(CURLME_OK, ExtraRefCnt::for_global_const)));
+ kphp::log::assertion((kphp::core::set_reference_counter_recursive(CURLME_BAD_HANDLE, ExtraRefCnt::for_global_const),
+ kphp::core::is_reference_counter_recursive(CURLME_BAD_HANDLE, ExtraRefCnt::for_global_const)));
+ kphp::log::assertion((kphp::core::set_reference_counter_recursive(CURLME_BAD_EASY_HANDLE, ExtraRefCnt::for_global_const),
+ kphp::core::is_reference_counter_recursive(CURLME_BAD_EASY_HANDLE, ExtraRefCnt::for_global_const)));
+ kphp::log::assertion((kphp::core::set_reference_counter_recursive(CURLME_OUT_OF_MEMORY, ExtraRefCnt::for_global_const),
+ kphp::core::is_reference_counter_recursive(CURLME_OUT_OF_MEMORY, ExtraRefCnt::for_global_const)));
+ kphp::log::assertion((kphp::core::set_reference_counter_recursive(CURLME_INTERNAL_ERROR, ExtraRefCnt::for_global_const),
+ kphp::core::is_reference_counter_recursive(CURLME_INTERNAL_ERROR, ExtraRefCnt::for_global_const)));
+ kphp::log::assertion((kphp::core::set_reference_counter_recursive(CURLME_BAD_SOCKET, ExtraRefCnt::for_global_const),
+ kphp::core::is_reference_counter_recursive(CURLME_BAD_SOCKET, ExtraRefCnt::for_global_const)));
+ kphp::log::assertion((kphp::core::set_reference_counter_recursive(CURLME_UNKNOWN_OPTION, ExtraRefCnt::for_global_const),
+ kphp::core::is_reference_counter_recursive(CURLME_UNKNOWN_OPTION, ExtraRefCnt::for_global_const)));
+ kphp::log::assertion((kphp::core::set_reference_counter_recursive(CURLME_ADDED_ALREADY, ExtraRefCnt::for_global_const),
+ kphp::core::is_reference_counter_recursive(CURLME_ADDED_ALREADY, ExtraRefCnt::for_global_const)));
+ kphp::log::assertion((kphp::core::set_reference_counter_recursive(CURLME_RECURSIVE_API_CALL, ExtraRefCnt::for_global_const),
+ kphp::core::is_reference_counter_recursive(CURLME_RECURSIVE_API_CALL, ExtraRefCnt::for_global_const)));
+ kphp::log::assertion((kphp::core::set_reference_counter_recursive(CURLME_WAKEUP_FAILURE, ExtraRefCnt::for_global_const),
+ kphp::core::is_reference_counter_recursive(CURLME_WAKEUP_FAILURE, ExtraRefCnt::for_global_const)));
+ kphp::log::assertion((kphp::core::set_reference_counter_recursive(CURLME_BAD_FUNCTION_ARGUMENT, ExtraRefCnt::for_global_const),
+ kphp::core::is_reference_counter_recursive(CURLME_BAD_FUNCTION_ARGUMENT, ExtraRefCnt::for_global_const)));
+ kphp::log::assertion((kphp::core::set_reference_counter_recursive(CURLME_ABORTED_BY_CALLBACK, ExtraRefCnt::for_global_const),
+ kphp::core::is_reference_counter_recursive(CURLME_ABORTED_BY_CALLBACK, ExtraRefCnt::for_global_const)));
+ kphp::log::assertion((kphp::core::set_reference_counter_recursive(CURLME_UNRECOVERABLE_POLL, ExtraRefCnt::for_global_const),
+ kphp::core::is_reference_counter_recursive(CURLME_UNRECOVERABLE_POLL, ExtraRefCnt::for_global_const)));
+ }
+
+ static const CurlImageState& get() noexcept;
+};
diff --git a/runtime-light/stdlib/curl/defs.h b/runtime-light/stdlib/curl/defs.h
index e2ac515867..f76e433bd2 100644
--- a/runtime-light/stdlib/curl/defs.h
+++ b/runtime-light/stdlib/curl/defs.h
@@ -5,6 +5,7 @@
#pragma once
#include
+#include
#include "runtime-light/stdlib/web-transfer-lib/defs.h"
@@ -283,3 +284,22 @@ enum class CURLPIPE : uint8_t {
};
} // namespace kphp::web::curl
+
+namespace kphp::web::curl::details {
+
+inline constexpr std::string_view CURLME_CALL_MULTI_PERFORM{"Please call curl_multi_perform() soon"};
+inline constexpr std::string_view CURLME_OK{"No error"};
+inline constexpr std::string_view CURLME_BAD_HANDLE{"Invalid multi handle"};
+inline constexpr std::string_view CURLME_BAD_EASY_HANDLE{"Invalid easy handle"};
+inline constexpr std::string_view CURLME_OUT_OF_MEMORY{"Out of memory"};
+inline constexpr std::string_view CURLME_INTERNAL_ERROR{"Internal error"};
+inline constexpr std::string_view CURLME_BAD_SOCKET{"Invalid socket argument"};
+inline constexpr std::string_view CURLME_UNKNOWN_OPTION{"Unknown option"};
+inline constexpr std::string_view CURLME_ADDED_ALREADY{"The easy handle is already added to a multi handle"};
+inline constexpr std::string_view CURLME_RECURSIVE_API_CALL{"API function called from within callback"};
+inline constexpr std::string_view CURLME_WAKEUP_FAILURE{"Wakeup is unavailable or failed"};
+inline constexpr std::string_view CURLME_BAD_FUNCTION_ARGUMENT{"A libcurl function was given a bad argument"};
+inline constexpr std::string_view CURLME_ABORTED_BY_CALLBACK{"Operation was aborted by an application callback"};
+inline constexpr std::string_view CURLME_UNRECOVERABLE_POLL{"Unrecoverable error in select/poll"};
+
+} // namespace kphp::web::curl::details