
On 8/28/25 14:54, Stefan Kober wrote:
This allows users to call API endpoints that require passing data in a generic way. Previously, only virCHMonitorPutNoContent was offered.
On-behalf-of: SAP stefan.kober@sap.com Signed-off-by: Stefan Kober <stefan.kober@cyberus-technology.de> --- src/ch/ch_monitor.c | 61 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+)
diff --git a/src/ch/ch_monitor.c b/src/ch/ch_monitor.c index d369236183..63c8425b4b 100644 --- a/src/ch/ch_monitor.c +++ b/src/ch/ch_monitor.c @@ -62,6 +62,10 @@ VIR_ONCE_GLOBAL_INIT(virCHMonitor); int virCHMonitorShutdownVMM(virCHMonitor *mon); int virCHMonitorPutNoContent(virCHMonitor *mon, const char *endpoint, domainLogContext *logCtxt); +int +virCHMonitorPut(virCHMonitor *mon, const char *endpoint, + const char *payload, domainLogContext *logCtxt, + virJSONValue** answer);
One argument per line please. Oh, and we like pointers to be declared as: virJSONValue **answer instead of virJSONValue** answer
static int virCHMonitorBuildCPUJson(virJSONValue *content, virDomainDef *vmdef) @@ -866,6 +870,63 @@ curl_callback(void *contents, size_t size, size_t nmemb, void *userp) return content_size; }
+int +virCHMonitorPut(virCHMonitor *mon, const char *endpoint, + const char *payload, domainLogContext *logCtxt, + virJSONValue** answer) +{ + VIR_LOCK_GUARD lock = virObjectLockGuard(mon); + g_autofree char *url = NULL; + int responseCode = 0; + struct curl_data data = {0}; + struct curl_slist *headers = NULL; + + url = g_strdup_printf("%s/%s", URL_ROOT, endpoint); + + /* reset all options of a libcurl session handle at first */ + curl_easy_reset(mon->handle); + + curl_easy_setopt(mon->handle, CURLOPT_UNIX_SOCKET_PATH, mon->socketpath); + curl_easy_setopt(mon->handle, CURLOPT_URL, url); + curl_easy_setopt(mon->handle, CURLOPT_UPLOAD, 1L); + curl_easy_setopt(mon->handle, CURLOPT_HTTPHEADER, NULL); + curl_easy_setopt(mon->handle, CURLOPT_INFILESIZE, 0L); + + headers = curl_slist_append(headers, "Content-Type: application/json");
I believe here you want "Accept: application/json" put inside 'headers', because if 'payload' is NULL, we are not sending anything, thus 'Content-Type' header field makes no sense.
+ + curl_easy_setopt(mon->handle, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(mon->handle, CURLOPT_WRITEFUNCTION, curl_callback); + curl_easy_setopt(mon->handle, CURLOPT_WRITEDATA, (void *)&data); + + if (payload) { + curl_easy_setopt(mon->handle, CURLOPT_POSTFIELDS, payload); + curl_easy_setopt(mon->handle, CURLOPT_CUSTOMREQUEST, "PUT"); + headers = curl_slist_append(headers, "Accept: application/json");
And here you want the 'Content-type: application/json' header field. Now, this got me thinking, since we set here 'application/json' type regardless of the actual 'payload' data type, would it make sense to turn 'payload' from 'const char *' to 'virJSONValue *'? This branch would then call virJSONValueToString().
+ } + + responseCode = virCHMonitorCurlPerform(mon->handle); + + data.content = g_realloc(data.content, data.size + 1); + data.content[data.size] = 0; + + if (logCtxt && data.size) { + /* Do this to append a NULL char at the end of data */ + domainLogContextWrite(logCtxt, "HTTP response code from CH: %d\n", responseCode); + domainLogContextWrite(logCtxt, "Response = %s\n", data.content); + } + + curl_slist_free_all(headers); + + if (responseCode != 200 && responseCode != 204) { + return -1; + } + + if (answer) + *answer = virJSONValueFromString(data.content);
I think data.content needs to be freed after this, no matter what. Otherwise it'll leak.
+ + return 0; +} + int virCHMonitorPutNoContent(virCHMonitor *mon, const char *endpoint, domainLogContext *logCtxt)
Michal