mirror of
https://github.com/morgan9e/systemd
synced 2026-04-14 00:14:32 +09:00
varlink: omit empty parameters field in JSON messages (#38922)
When varlink parameters are empty, omit the "parameters" field entirely
rather than sending "parameters":{}. This reduces message size and
follows varlink specification which allows parameters to be omitted.
The implementation supports three equivalent representations for empty
parameters: field omission, JSON null, and empty object {}. All three
are accepted on input for backward compatibility.
Fixes: #38474
This commit is contained in:
@@ -44,6 +44,13 @@
|
||||
<citerefentry><refentrytitle>sd-json</refentrytitle><manvolnum>3</manvolnum></citerefentry> API for JSON
|
||||
serialization, deserialization and manipulation.</para>
|
||||
|
||||
<para>Canonical encoding rules: sd-varlink omits the <literal>"parameters"</literal> member on the wire in replies,
|
||||
errors, and notifications when there are no parameters to transmit. This reduces message size and
|
||||
avoids ambiguity. Receivers must be tolerant and accept any of the following encodings for the
|
||||
absence of parameters: an omitted <literal>"parameters"</literal> key (preferred), a JSON <literal>null</literal>
|
||||
value, or an empty object <literal>{}</literal>. When decoding, sd-varlink treats JSON <literal>null</literal>
|
||||
as if the member was omitted.</para>
|
||||
|
||||
<para>The <citerefentry><refentrytitle>varlinkctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> tool
|
||||
makes the functionality implemented by sd-varlink available from the command line.</para>
|
||||
</refsect1>
|
||||
|
||||
@@ -170,6 +170,7 @@ enum {
|
||||
_JSON_BUILD_PAIR_STRV_NON_EMPTY,
|
||||
_JSON_BUILD_PAIR_STRV_ENV_PAIR_NON_EMPTY,
|
||||
_JSON_BUILD_PAIR_VARIANT_NON_NULL,
|
||||
_JSON_BUILD_PAIR_VARIANT_NON_EMPTY,
|
||||
/* _SD_JSON_BUILD_PAIR_VARIANT_ARRAY_NON_EMPTY, */
|
||||
_JSON_BUILD_PAIR_BYTE_ARRAY_NON_EMPTY,
|
||||
_JSON_BUILD_PAIR_IN4_ADDR_NON_NULL,
|
||||
@@ -218,6 +219,7 @@ enum {
|
||||
#define JSON_BUILD_PAIR_STRV_NON_EMPTY(name, l) _JSON_BUILD_PAIR_STRV_NON_EMPTY, (const char*) { name }, (char**) { l }
|
||||
#define JSON_BUILD_PAIR_STRV_ENV_PAIR_NON_EMPTY(name, l) _JSON_BUILD_PAIR_STRV_ENV_PAIR_NON_EMPTY, (const char*) { name }, (char**) { l }
|
||||
#define JSON_BUILD_PAIR_VARIANT_NON_NULL(name, v) _JSON_BUILD_PAIR_VARIANT_NON_NULL, (const char*) { name }, (sd_json_variant*) { v }
|
||||
#define JSON_BUILD_PAIR_VARIANT_NON_EMPTY(name, v) _JSON_BUILD_PAIR_VARIANT_NON_EMPTY, (const char*) { name }, (sd_json_variant*) { v }
|
||||
#define JSON_BUILD_PAIR_BYTE_ARRAY_NON_EMPTY(name, v, n) _JSON_BUILD_PAIR_BYTE_ARRAY_NON_EMPTY, (const char*) { name }, (const void*) { v }, (size_t) { n }
|
||||
#define JSON_BUILD_PAIR_IN4_ADDR_NON_NULL(name, v) _JSON_BUILD_PAIR_IN4_ADDR_NON_NULL, (const char*) { name }, (const struct in_addr*) { v }
|
||||
#define JSON_BUILD_PAIR_IN6_ADDR_NON_NULL(name, v) _JSON_BUILD_PAIR_IN6_ADDR_NON_NULL, (const char*) { name }, (const struct in6_addr*) { v }
|
||||
|
||||
@@ -4445,7 +4445,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
n_subtract = 2; /* we generated two item */
|
||||
n_subtract = 2; /* we generated two items */
|
||||
|
||||
current->expect = EXPECT_OBJECT_KEY;
|
||||
break;
|
||||
@@ -4475,7 +4475,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
n_subtract = 2; /* we generated two item */
|
||||
n_subtract = 2; /* we generated two items */
|
||||
|
||||
current->expect = EXPECT_OBJECT_KEY;
|
||||
break;
|
||||
@@ -4503,7 +4503,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
n_subtract = 2; /* we generated two item */
|
||||
n_subtract = 2; /* we generated two items */
|
||||
|
||||
current->expect = EXPECT_OBJECT_KEY;
|
||||
break;
|
||||
@@ -4530,7 +4530,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
n_subtract = 2; /* we generated two item */
|
||||
n_subtract = 2; /* we generated two items */
|
||||
|
||||
current->expect = EXPECT_OBJECT_KEY;
|
||||
break;
|
||||
@@ -4567,7 +4567,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
n_subtract = 2; /* we generated two item */
|
||||
n_subtract = 2; /* we generated two items */
|
||||
|
||||
current->expect = EXPECT_OBJECT_KEY;
|
||||
break;
|
||||
@@ -4593,7 +4593,33 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) {
|
||||
add_more = sd_json_variant_ref(v);
|
||||
}
|
||||
|
||||
n_subtract = 2; /* we generated two item */
|
||||
n_subtract = 2; /* we generated two items */
|
||||
|
||||
current->expect = EXPECT_OBJECT_KEY;
|
||||
break;
|
||||
}
|
||||
|
||||
case _JSON_BUILD_PAIR_VARIANT_NON_EMPTY: {
|
||||
sd_json_variant *v;
|
||||
const char *n;
|
||||
|
||||
if (current->expect != EXPECT_OBJECT_KEY) {
|
||||
r = -EINVAL;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
n = va_arg(ap, const char *);
|
||||
v = va_arg(ap, sd_json_variant *);
|
||||
|
||||
if (v && !sd_json_variant_is_blank_object(v) && current->n_suppress == 0) {
|
||||
r = sd_json_variant_new_string(&add, n);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
add_more = sd_json_variant_ref(v);
|
||||
}
|
||||
|
||||
n_subtract = 2; /* we generated two items */
|
||||
|
||||
current->expect = EXPECT_OBJECT_KEY;
|
||||
break;
|
||||
@@ -4623,7 +4649,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
n_subtract = 2; /* we generated two item */
|
||||
n_subtract = 2; /* we generated two items */
|
||||
|
||||
current->expect = EXPECT_OBJECT_KEY;
|
||||
break;
|
||||
@@ -4651,7 +4677,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
n_subtract = 2; /* we generated two item */
|
||||
n_subtract = 2; /* we generated two items */
|
||||
|
||||
current->expect = EXPECT_OBJECT_KEY;
|
||||
break;
|
||||
@@ -4679,7 +4705,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
n_subtract = 2; /* we generated two item */
|
||||
n_subtract = 2; /* we generated two items */
|
||||
|
||||
current->expect = EXPECT_OBJECT_KEY;
|
||||
break;
|
||||
@@ -4709,7 +4735,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
n_subtract = 2; /* we generated two item */
|
||||
n_subtract = 2; /* we generated two items */
|
||||
|
||||
current->expect = EXPECT_OBJECT_KEY;
|
||||
break;
|
||||
@@ -4737,7 +4763,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
n_subtract = 2; /* we generated two item */
|
||||
n_subtract = 2; /* we generated two items */
|
||||
|
||||
current->expect = EXPECT_OBJECT_KEY;
|
||||
break;
|
||||
@@ -4765,7 +4791,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
n_subtract = 2; /* we generated two item */
|
||||
n_subtract = 2; /* we generated two items */
|
||||
|
||||
current->expect = EXPECT_OBJECT_KEY;
|
||||
break;
|
||||
@@ -4795,7 +4821,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
n_subtract = 2; /* we generated two item */
|
||||
n_subtract = 2; /* we generated two items */
|
||||
|
||||
current->expect = EXPECT_OBJECT_KEY;
|
||||
break;
|
||||
@@ -4825,7 +4851,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
n_subtract = 2; /* we generated two item */
|
||||
n_subtract = 2; /* we generated two items */
|
||||
|
||||
current->expect = EXPECT_OBJECT_KEY;
|
||||
break;
|
||||
@@ -4887,7 +4913,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) {
|
||||
}
|
||||
}
|
||||
|
||||
n_subtract = 2; /* we generated two item */
|
||||
n_subtract = 2; /* we generated two items */
|
||||
|
||||
current->expect = EXPECT_OBJECT_KEY;
|
||||
break;
|
||||
@@ -4923,7 +4949,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
n_subtract = 2; /* we generated two item */
|
||||
n_subtract = 2; /* we generated two items */
|
||||
|
||||
current->expect = EXPECT_OBJECT_KEY;
|
||||
break;
|
||||
@@ -4951,7 +4977,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
n_subtract = 2; /* we generated two item */
|
||||
n_subtract = 2; /* we generated two items */
|
||||
|
||||
current->expect = EXPECT_OBJECT_KEY;
|
||||
break;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "alloc-util.h"
|
||||
#include "ansi-color.h"
|
||||
#include "extract-word.h"
|
||||
#include "json-internal.h"
|
||||
#include "json-util.h"
|
||||
#include "log.h"
|
||||
#include "memstream-util.h"
|
||||
@@ -1793,11 +1794,9 @@ static int varlink_idl_validate_symbol(const sd_varlink_symbol *symbol, sd_json_
|
||||
assert(symbol);
|
||||
assert(!IN_SET(symbol->symbol_type, _SD_VARLINK_SYMBOL_COMMENT, _SD_VARLINK_INTERFACE_COMMENT));
|
||||
|
||||
if (!v) {
|
||||
if (reterr_bad_field)
|
||||
*reterr_bad_field = NULL;
|
||||
return varlink_idl_log(SYNTHETIC_ERRNO(EMEDIUMTYPE), "Null object passed, refusing.");
|
||||
}
|
||||
/* Consider a NULL pointer equivalent to an empty object */
|
||||
if (!v)
|
||||
v = JSON_VARIANT_MAGIC_EMPTY_OBJECT;
|
||||
|
||||
switch (symbol->symbol_type) {
|
||||
|
||||
|
||||
@@ -1020,6 +1020,7 @@ static int varlink_test_timeout(sd_varlink *v) {
|
||||
}
|
||||
|
||||
static int varlink_dispatch_local_error(sd_varlink *v, const char *error) {
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *empty = NULL;
|
||||
int r;
|
||||
|
||||
assert(v);
|
||||
@@ -1028,7 +1029,11 @@ static int varlink_dispatch_local_error(sd_varlink *v, const char *error) {
|
||||
if (!v->reply_callback)
|
||||
return 0;
|
||||
|
||||
r = v->reply_callback(v, NULL, error, SD_VARLINK_REPLY_ERROR|SD_VARLINK_REPLY_LOCAL, v->userdata);
|
||||
r = sd_json_variant_new_object(&empty, NULL, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = v->reply_callback(v, empty, error, SD_VARLINK_REPLY_ERROR|SD_VARLINK_REPLY_LOCAL, v->userdata);
|
||||
if (r < 0)
|
||||
varlink_log_errno(v, r, "Reply callback returned error, ignoring: %m");
|
||||
|
||||
@@ -1061,25 +1066,23 @@ static int varlink_dispatch_disconnect(sd_varlink *v) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int varlink_sanitize_parameters(sd_json_variant **v) {
|
||||
static int varlink_sanitize_incoming_parameters(sd_json_variant **v) {
|
||||
int r;
|
||||
|
||||
assert(v);
|
||||
|
||||
/* Varlink always wants a parameters list, hence make one if the caller doesn't want any */
|
||||
if (!*v)
|
||||
return sd_json_variant_new_object(v, NULL, 0);
|
||||
if (sd_json_variant_is_null(*v)) {
|
||||
sd_json_variant *empty;
|
||||
|
||||
/* Convert NULL or JSON null to empty object for method handlers (backward compatibility) */
|
||||
if (!*v || sd_json_variant_is_null(*v)) {
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *empty = NULL;
|
||||
r = sd_json_variant_new_object(&empty, NULL, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* sd_json_variant_unref() is a NOP if *v is NULL */
|
||||
sd_json_variant_unref(*v);
|
||||
*v = empty;
|
||||
*v = TAKE_PTR(empty);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Ensure we have an object */
|
||||
if (!sd_json_variant_is_object(*v))
|
||||
return -EINVAL;
|
||||
|
||||
@@ -1146,7 +1149,7 @@ static int varlink_dispatch_reply(sd_varlink *v) {
|
||||
if (error && FLAGS_SET(flags, SD_VARLINK_REPLY_CONTINUES))
|
||||
goto invalid;
|
||||
|
||||
r = varlink_sanitize_parameters(¶meters);
|
||||
r = varlink_sanitize_incoming_parameters(¶meters);
|
||||
if (r < 0)
|
||||
goto invalid;
|
||||
|
||||
@@ -1327,7 +1330,7 @@ static int varlink_dispatch_method(sd_varlink *v) {
|
||||
if (!method)
|
||||
goto invalid;
|
||||
|
||||
r = varlink_sanitize_parameters(¶meters);
|
||||
r = varlink_sanitize_incoming_parameters(¶meters);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
@@ -1575,13 +1578,14 @@ _public_ int sd_varlink_get_current_parameters(sd_varlink *v, sd_json_variant **
|
||||
if (!v->current)
|
||||
return -ENODATA;
|
||||
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
p = sd_json_variant_by_key(v->current, "parameters");
|
||||
if (!p)
|
||||
return -ENODATA;
|
||||
|
||||
if (ret)
|
||||
*ret = sd_json_variant_ref(p);
|
||||
if (!p || sd_json_variant_is_null(p))
|
||||
return sd_json_variant_new_object(ret, NULL, 0);
|
||||
|
||||
*ret = sd_json_variant_ref(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2024,14 +2028,10 @@ _public_ int sd_varlink_send(sd_varlink *v, const char *method, sd_json_variant
|
||||
if (!IN_SET(v->state, VARLINK_IDLE_CLIENT, VARLINK_AWAITING_REPLY))
|
||||
return varlink_log_errno(v, SYNTHETIC_ERRNO(EBUSY), "Connection busy.");
|
||||
|
||||
r = varlink_sanitize_parameters(¶meters);
|
||||
if (r < 0)
|
||||
return varlink_log_errno(v, r, "Failed to sanitize parameters: %m");
|
||||
|
||||
r = sd_json_buildo(
|
||||
&m,
|
||||
SD_JSON_BUILD_PAIR("method", SD_JSON_BUILD_STRING(method)),
|
||||
SD_JSON_BUILD_PAIR("parameters", SD_JSON_BUILD_VARIANT(parameters)),
|
||||
JSON_BUILD_PAIR_VARIANT_NON_EMPTY("parameters", parameters),
|
||||
SD_JSON_BUILD_PAIR("oneway", SD_JSON_BUILD_BOOLEAN(true)));
|
||||
if (r < 0)
|
||||
return varlink_log_errno(v, r, "Failed to build json message: %m");
|
||||
@@ -2076,14 +2076,10 @@ _public_ int sd_varlink_invoke(sd_varlink *v, const char *method, sd_json_varian
|
||||
if (!IN_SET(v->state, VARLINK_IDLE_CLIENT, VARLINK_AWAITING_REPLY))
|
||||
return varlink_log_errno(v, SYNTHETIC_ERRNO(EBUSY), "Connection busy.");
|
||||
|
||||
r = varlink_sanitize_parameters(¶meters);
|
||||
if (r < 0)
|
||||
return varlink_log_errno(v, r, "Failed to sanitize parameters: %m");
|
||||
|
||||
r = sd_json_buildo(
|
||||
&m,
|
||||
SD_JSON_BUILD_PAIR("method", SD_JSON_BUILD_STRING(method)),
|
||||
SD_JSON_BUILD_PAIR("parameters", SD_JSON_BUILD_VARIANT(parameters)));
|
||||
JSON_BUILD_PAIR_VARIANT_NON_EMPTY("parameters", parameters));
|
||||
if (r < 0)
|
||||
return varlink_log_errno(v, r, "Failed to build json message: %m");
|
||||
|
||||
@@ -2130,14 +2126,10 @@ _public_ int sd_varlink_observe(sd_varlink *v, const char *method, sd_json_varia
|
||||
if (v->state != VARLINK_IDLE_CLIENT)
|
||||
return varlink_log_errno(v, SYNTHETIC_ERRNO(EBUSY), "Connection busy.");
|
||||
|
||||
r = varlink_sanitize_parameters(¶meters);
|
||||
if (r < 0)
|
||||
return varlink_log_errno(v, r, "Failed to sanitize parameters: %m");
|
||||
|
||||
r = sd_json_buildo(
|
||||
&m,
|
||||
SD_JSON_BUILD_PAIR("method", SD_JSON_BUILD_STRING(method)),
|
||||
SD_JSON_BUILD_PAIR("parameters", SD_JSON_BUILD_VARIANT(parameters)),
|
||||
JSON_BUILD_PAIR_VARIANT_NON_EMPTY("parameters", parameters),
|
||||
SD_JSON_BUILD_PAIR("more", SD_JSON_BUILD_BOOLEAN(true)));
|
||||
if (r < 0)
|
||||
return varlink_log_errno(v, r, "Failed to build json message: %m");
|
||||
@@ -2195,14 +2187,10 @@ _public_ int sd_varlink_call_full(
|
||||
* that we can assign a new reply shortly. */
|
||||
varlink_clear_current(v);
|
||||
|
||||
r = varlink_sanitize_parameters(¶meters);
|
||||
if (r < 0)
|
||||
return varlink_log_errno(v, r, "Failed to sanitize parameters: %m");
|
||||
|
||||
r = sd_json_buildo(
|
||||
&m,
|
||||
SD_JSON_BUILD_PAIR("method", SD_JSON_BUILD_STRING(method)),
|
||||
SD_JSON_BUILD_PAIR("parameters", SD_JSON_BUILD_VARIANT(parameters)));
|
||||
JSON_BUILD_PAIR_VARIANT_NON_EMPTY("parameters", parameters));
|
||||
if (r < 0)
|
||||
return varlink_log_errno(v, r, "Failed to build json message: %m");
|
||||
|
||||
@@ -2353,14 +2341,10 @@ _public_ int sd_varlink_collect_full(
|
||||
* that we can assign a new reply shortly. */
|
||||
varlink_clear_current(v);
|
||||
|
||||
r = varlink_sanitize_parameters(¶meters);
|
||||
if (r < 0)
|
||||
return varlink_log_errno(v, r, "Failed to sanitize parameters: %m");
|
||||
|
||||
r = sd_json_buildo(
|
||||
&m,
|
||||
SD_JSON_BUILD_PAIR("method", SD_JSON_BUILD_STRING(method)),
|
||||
SD_JSON_BUILD_PAIR("parameters", SD_JSON_BUILD_VARIANT(parameters)),
|
||||
JSON_BUILD_PAIR_VARIANT_NON_EMPTY("parameters", parameters),
|
||||
SD_JSON_BUILD_PAIR("more", SD_JSON_BUILD_BOOLEAN(true)));
|
||||
if (r < 0)
|
||||
return varlink_log_errno(v, r, "Failed to build json message: %m");
|
||||
@@ -2501,14 +2485,7 @@ _public_ int sd_varlink_reply(sd_varlink *v, sd_json_variant *parameters) {
|
||||
VARLINK_PENDING_METHOD, VARLINK_PENDING_METHOD_MORE))
|
||||
return -EBUSY;
|
||||
|
||||
r = varlink_sanitize_parameters(¶meters);
|
||||
if (r < 0)
|
||||
return varlink_log_errno(v, r, "Failed to sanitize parameters: %m");
|
||||
|
||||
r = sd_json_buildo(&m, SD_JSON_BUILD_PAIR("parameters", SD_JSON_BUILD_VARIANT(parameters)));
|
||||
if (r < 0)
|
||||
return varlink_log_errno(v, r, "Failed to build json message: %m");
|
||||
|
||||
/* Validate parameters BEFORE sanitization */
|
||||
if (v->current_method) {
|
||||
const char *bad_field = NULL;
|
||||
|
||||
@@ -2519,6 +2496,10 @@ _public_ int sd_varlink_reply(sd_varlink *v, sd_json_variant *parameters) {
|
||||
v->current_method->name, strna(bad_field));
|
||||
}
|
||||
|
||||
r = sd_json_buildo(&m, JSON_BUILD_PAIR_VARIANT_NON_EMPTY("parameters", parameters));
|
||||
if (r < 0)
|
||||
return varlink_log_errno(v, r, "Failed to build json message: %m");
|
||||
|
||||
r = varlink_enqueue_json(v, m);
|
||||
if (r < 0)
|
||||
return varlink_log_errno(v, r, "Failed to enqueue json message: %m");
|
||||
@@ -2588,17 +2569,7 @@ _public_ int sd_varlink_error(sd_varlink *v, const char *error_id, sd_json_varia
|
||||
* the callers don't need to do this explicitly. */
|
||||
sd_varlink_reset_fds(v);
|
||||
|
||||
r = varlink_sanitize_parameters(¶meters);
|
||||
if (r < 0)
|
||||
return varlink_log_errno(v, r, "Failed to sanitize parameters: %m");
|
||||
|
||||
r = sd_json_buildo(
|
||||
&m,
|
||||
SD_JSON_BUILD_PAIR("error", SD_JSON_BUILD_STRING(error_id)),
|
||||
SD_JSON_BUILD_PAIR("parameters", SD_JSON_BUILD_VARIANT(parameters)));
|
||||
if (r < 0)
|
||||
return varlink_log_errno(v, r, "Failed to build json message: %m");
|
||||
|
||||
/* Validate parameters BEFORE sanitization */
|
||||
sd_varlink_symbol *symbol = hashmap_get(v->server->symbols, error_id);
|
||||
if (!symbol)
|
||||
varlink_log(v, "No interface description defined for error '%s', not validating.", error_id);
|
||||
@@ -2612,6 +2583,13 @@ _public_ int sd_varlink_error(sd_varlink *v, const char *error_id, sd_json_varia
|
||||
error_id, strna(bad_field));
|
||||
}
|
||||
|
||||
r = sd_json_buildo(
|
||||
&m,
|
||||
SD_JSON_BUILD_PAIR("error", SD_JSON_BUILD_STRING(error_id)),
|
||||
JSON_BUILD_PAIR_VARIANT_NON_EMPTY("parameters", parameters));
|
||||
if (r < 0)
|
||||
return varlink_log_errno(v, r, "Failed to build json message: %m");
|
||||
|
||||
r = varlink_enqueue_json(v, m);
|
||||
if (r < 0)
|
||||
return varlink_log_errno(v, r, "Failed to enqueue json message: %m");
|
||||
@@ -2726,17 +2704,7 @@ _public_ int sd_varlink_notify(sd_varlink *v, sd_json_variant *parameters) {
|
||||
if (!IN_SET(v->state, VARLINK_PROCESSING_METHOD_MORE, VARLINK_PENDING_METHOD_MORE))
|
||||
return varlink_log_errno(v, SYNTHETIC_ERRNO(EBUSY), "Connection busy.");
|
||||
|
||||
r = varlink_sanitize_parameters(¶meters);
|
||||
if (r < 0)
|
||||
return varlink_log_errno(v, r, "Failed to sanitize parameters: %m");
|
||||
|
||||
r = sd_json_buildo(
|
||||
&m,
|
||||
SD_JSON_BUILD_PAIR("parameters", SD_JSON_BUILD_VARIANT(parameters)),
|
||||
SD_JSON_BUILD_PAIR("continues", SD_JSON_BUILD_BOOLEAN(true)));
|
||||
if (r < 0)
|
||||
return varlink_log_errno(v, r, "Failed to build json message: %m");
|
||||
|
||||
/* Validate parameters BEFORE sanitization */
|
||||
if (v->current_method) {
|
||||
const char *bad_field = NULL;
|
||||
|
||||
@@ -2750,6 +2718,13 @@ _public_ int sd_varlink_notify(sd_varlink *v, sd_json_variant *parameters) {
|
||||
v->current_method->name, strna(bad_field));
|
||||
}
|
||||
|
||||
r = sd_json_buildo(
|
||||
&m,
|
||||
JSON_BUILD_PAIR_VARIANT_NON_EMPTY("parameters", parameters),
|
||||
SD_JSON_BUILD_PAIR("continues", SD_JSON_BUILD_BOOLEAN(true)));
|
||||
if (r < 0)
|
||||
return varlink_log_errno(v, r, "Failed to build json message: %m");
|
||||
|
||||
r = varlink_enqueue_json(v, m);
|
||||
if (r < 0)
|
||||
return varlink_log_errno(v, r, "Failed to enqueue json message: %m");
|
||||
@@ -2783,6 +2758,7 @@ _public_ int sd_varlink_dispatch(sd_varlink *v, sd_json_variant *parameters, con
|
||||
|
||||
/* A wrapper around json_dispatch_full() that returns a nice InvalidParameter error if we hit a problem with some field. */
|
||||
|
||||
/* sd_json_dispatch_full() now handles NULL parameters gracefully */
|
||||
r = sd_json_dispatch_full(parameters, dispatch_table, /* bad= */ NULL, /* flags= */ 0, userdata, &bad_field);
|
||||
if (r < 0) {
|
||||
if (bad_field)
|
||||
|
||||
@@ -47,6 +47,7 @@ int varlink_method_ping(sd_varlink *link, sd_json_variant *parameters, sd_varlin
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(parameters);
|
||||
|
||||
r = sd_varlink_dispatch(link, parameters, /* dispatch_table= */ NULL, /* userdata= */ NULL);
|
||||
if (r != 0)
|
||||
|
||||
@@ -205,6 +205,9 @@ static int overload_reply(sd_varlink *link, sd_json_variant *parameters, const c
|
||||
|
||||
log_debug("Over reply triggered with error: %s", strna(error_id));
|
||||
ASSERT_STREQ(error_id, SD_VARLINK_ERROR_DISCONNECTED);
|
||||
/* Local disconnect errors carry empty parameters. Ensure we propagate
|
||||
* a consistent empty object for API reliability. */
|
||||
ASSERT_TRUE(sd_json_variant_is_blank_object(parameters));
|
||||
sd_event_exit(sd_varlink_get_event(link), 0);
|
||||
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user