common/json_stream.c: provide explicit json_add_primitive_fmt and json_add_str_fmt routines.

Rather than a generic "add member", provide two routines: one which
doesn't quote, and one which does.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell
2022-07-04 13:22:35 +09:30
committed by neil saitug
parent 36a29fbfbc
commit dbae5ae569
9 changed files with 118 additions and 85 deletions

View File

@@ -128,15 +128,6 @@ void json_stream_flush(struct json_stream *js)
io_wake(js); io_wake(js);
} }
char *json_member_direct(struct json_stream *js,
const char *fieldname, size_t extra)
{
char *dest;
dest = json_out_member_direct(js->jout, fieldname, extra);
return dest;
}
void json_array_start(struct json_stream *js, const char *fieldname) void json_array_start(struct json_stream *js, const char *fieldname)
{ {
json_out_start(js->jout, fieldname, '['); json_out_start(js->jout, fieldname, '[');
@@ -157,18 +148,55 @@ void json_object_end(struct json_stream *js)
json_out_end(js->jout, '}'); json_out_end(js->jout, '}');
} }
void json_add_member(struct json_stream *js, void json_add_primitive_fmt(struct json_stream *js,
const char *fieldname, const char *fieldname,
bool quote, const char *fmt, ...)
const char *fmt, ...)
{ {
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
json_out_addv(js->jout, fieldname, quote, fmt, ap); json_out_addv(js->jout, fieldname, false, fmt, ap);
va_end(ap); va_end(ap);
} }
void json_add_str_fmt(struct json_stream *js,
const char *fieldname,
const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
json_out_addv(js->jout, fieldname, true, fmt, ap);
va_end(ap);
}
void json_add_primitive(struct json_stream *js,
const char *fieldname,
const char *val TAKES)
{
json_add_primitive_fmt(js, fieldname, "%s", val);
if (taken(val))
tal_free(val);
}
void json_add_string(struct json_stream *js,
const char *fieldname,
const char *str TAKES)
{
json_out_addstr(js->jout, fieldname, str);
if (taken(str))
tal_free(str);
}
static char *json_member_direct(struct json_stream *js,
const char *fieldname, size_t extra)
{
char *dest;
dest = json_out_member_direct(js->jout, fieldname, extra);
return dest;
}
void json_add_jsonstr(struct json_stream *js, void json_add_jsonstr(struct json_stream *js,
const char *fieldname, const char *fieldname,
const char *jsonstr) const char *jsonstr)
@@ -225,76 +253,62 @@ struct io_plan *json_stream_output_(struct json_stream *js,
void json_add_num(struct json_stream *result, const char *fieldname, unsigned int value) void json_add_num(struct json_stream *result, const char *fieldname, unsigned int value)
{ {
json_add_member(result, fieldname, false, "%u", value); json_add_primitive_fmt(result, fieldname, "%u", value);
} }
void json_add_u64(struct json_stream *result, const char *fieldname, void json_add_u64(struct json_stream *result, const char *fieldname,
uint64_t value) uint64_t value)
{ {
json_add_member(result, fieldname, false, "%"PRIu64, value); json_add_primitive_fmt(result, fieldname, "%"PRIu64, value);
} }
void json_add_s64(struct json_stream *result, const char *fieldname, void json_add_s64(struct json_stream *result, const char *fieldname,
int64_t value) int64_t value)
{ {
json_add_member(result, fieldname, false, "%"PRIi64, value); json_add_primitive_fmt(result, fieldname, "%"PRIi64, value);
} }
void json_add_u32(struct json_stream *result, const char *fieldname, void json_add_u32(struct json_stream *result, const char *fieldname,
uint32_t value) uint32_t value)
{ {
json_add_member(result, fieldname, false, "%u", value); json_add_primitive_fmt(result, fieldname, "%u", value);
} }
void json_add_s32(struct json_stream *result, const char *fieldname, void json_add_s32(struct json_stream *result, const char *fieldname,
int32_t value) int32_t value)
{ {
json_add_member(result, fieldname, false, "%d", value); json_add_primitive_fmt(result, fieldname, "%d", value);
}
void json_add_literal(struct json_stream *result, const char *fieldname,
const char *literal, int len)
{
/* Literal may contain quotes, so bypass normal checks */
char *dest = json_member_direct(result, fieldname, len);
memcpy(dest, literal, len);
} }
void json_add_stringn(struct json_stream *result, const char *fieldname, void json_add_stringn(struct json_stream *result, const char *fieldname,
const char *value TAKES, size_t value_len) const char *value TAKES, size_t value_len)
{ {
json_add_member(result, fieldname, true, "%.*s", (int)value_len, value); json_add_str_fmt(result, fieldname, "%.*s", (int)value_len, value);
if (taken(value)) if (taken(value))
tal_free(value); tal_free(value);
} }
void json_add_string(struct json_stream *result, const char *fieldname, const char *value TAKES)
{
json_add_stringn(result, fieldname, value, strlen(value));
}
void json_add_bool(struct json_stream *result, const char *fieldname, bool value) void json_add_bool(struct json_stream *result, const char *fieldname, bool value)
{ {
json_add_member(result, fieldname, false, value ? "true" : "false"); json_add_primitive(result, fieldname, value ? "true" : "false");
} }
void json_add_null(struct json_stream *stream, const char *fieldname) void json_add_null(struct json_stream *stream, const char *fieldname)
{ {
json_add_member(stream, fieldname, false, "null"); json_add_primitive(stream, fieldname, "null");
} }
void json_add_hex(struct json_stream *js, const char *fieldname, void json_add_hex(struct json_stream *js, const char *fieldname,
const void *data, size_t len) const void *data, size_t len)
{ {
/* Size without NUL term */ /* Size without NUL term */
size_t hexlen = hex_str_size(len) - 1; size_t hexlen = hex_str_size(len);
char *dest; char str[hexlen];
dest = json_member_direct(js, fieldname, 1 + hexlen + 1); if (!hex_encode(data, len, str, hexlen))
dest[0] = '"';
if (!hex_encode(data, len, dest + 1, hexlen + 1))
abort(); abort();
dest[1+hexlen] = '"';
json_add_string(js, fieldname, str);
} }
void json_add_hex_talarr(struct json_stream *result, void json_add_hex_talarr(struct json_stream *result,
@@ -321,8 +335,9 @@ void json_add_escaped_string(struct json_stream *result, const char *fieldname,
void json_add_timeabs(struct json_stream *result, const char *fieldname, void json_add_timeabs(struct json_stream *result, const char *fieldname,
struct timeabs t) struct timeabs t)
{ {
json_add_member(result, fieldname, false, "%" PRIu64 ".%03" PRIu64, json_add_primitive_fmt(result, fieldname,
(u64)t.ts.tv_sec, (u64)t.ts.tv_nsec / 1000000); "%" PRIu64 ".%03" PRIu64,
(u64)t.ts.tv_sec, (u64)t.ts.tv_nsec / 1000000);
} }
void json_add_time(struct json_stream *result, const char *fieldname, void json_add_time(struct json_stream *result, const char *fieldname,
@@ -365,7 +380,7 @@ void json_add_tok(struct json_stream *result, const char *fieldname,
void json_add_errcode(struct json_stream *result, const char *fieldname, void json_add_errcode(struct json_stream *result, const char *fieldname,
errcode_t code) errcode_t code)
{ {
json_add_member(result, fieldname, false, "%"PRIerrcode, code); json_add_primitive_fmt(result, fieldname, "%" PRIerrcode, code);
} }
void json_add_invstring(struct json_stream *result, const char *invstring) void json_add_invstring(struct json_stream *result, const char *invstring)
@@ -431,17 +446,17 @@ void json_add_outpoint(struct json_stream *result, const char *fieldname,
{ {
char hex[hex_str_size(sizeof(out->txid))]; char hex[hex_str_size(sizeof(out->txid))];
bitcoin_txid_to_hex(&out->txid, hex, sizeof(hex)); bitcoin_txid_to_hex(&out->txid, hex, sizeof(hex));
json_add_member(result, fieldname, true, "%s:%d", hex, out->n); json_add_str_fmt(result, fieldname, "%s:%d", hex, out->n);
} }
void json_add_short_channel_id(struct json_stream *response, void json_add_short_channel_id(struct json_stream *response,
const char *fieldname, const char *fieldname,
const struct short_channel_id *scid) const struct short_channel_id *scid)
{ {
json_add_member(response, fieldname, true, "%dx%dx%d", json_add_str_fmt(response, fieldname, "%dx%dx%d",
short_channel_id_blocknum(scid), short_channel_id_blocknum(scid),
short_channel_id_txnum(scid), short_channel_id_txnum(scid),
short_channel_id_outnum(scid)); short_channel_id_outnum(scid));
} }
void json_add_address(struct json_stream *response, const char *fieldname, void json_add_address(struct json_stream *response, const char *fieldname,

View File

@@ -107,19 +107,50 @@ void json_object_end(struct json_stream *js);
void json_stream_append(struct json_stream *js, const char *str, size_t len); void json_stream_append(struct json_stream *js, const char *str, size_t len);
/** /**
* json_add_member - add a generic member. * json_add_primitive_fmt - add an unquoted literal member.
* @js: the json_stream. * @js: the json_stream.
* @fieldname: fieldname (if in object), otherwise must be NULL. * @fieldname: fieldname (if in object), otherwise must be NULL.
* @quote: true if should be escaped and wrapped in "".
* @fmt...: the printf-style format * @fmt...: the printf-style format
*
* The resulting string from @fmt is escaped if quote is true:
* see json_member_direct to avoid quoting.
*/ */
void json_add_member(struct json_stream *js, void json_add_primitive_fmt(struct json_stream *js,
const char *fieldname,
const char *fmt, ...) PRINTF_FMT(3,4);
/**
* json_add_primitive - add an unquoted literal member.
* @js: the json_stream.
* @fieldname: fieldname (if in object), otherwise must be NULL.
* @val: the primitive
*/
void json_add_primitive(struct json_stream *js,
const char *fieldname,
const char *val TAKES);
/**
* json_add_str_fmt - add a string member (printf-style).
* @js: the json_stream.
* @fieldname: fieldname (if in object), otherwise must be NULL.
* @fmt...: the printf-style format
*/
void json_add_str_fmt(struct json_stream *js,
const char *fieldname,
const char *fmt, ...) PRINTF_FMT(3,4);
/**
* json_add_string - add a string member.
* @js: the json_stream.
* @fieldname: fieldname (if in object), otherwise must be NULL.
* @str: the string
*/
void json_add_string(struct json_stream *js,
const char *fieldname, const char *fieldname,
bool quote, const char *str TAKES);
const char *fmt, ...) PRINTF_FMT(4,5);
/* '"fieldname" : "value"' or '"value"' if fieldname is NULL. String must
* already be JSON escaped as necessary. */
void json_add_escaped_string(struct json_stream *result,
const char *fieldname,
const struct json_escape *esc TAKES);
/** /**
* json_add_jsonstr - add a JSON entity in a string that is already * json_add_jsonstr - add a JSON entity in a string that is already
@@ -133,17 +164,6 @@ void json_add_jsonstr(struct json_stream *js,
const char *fieldname, const char *fieldname,
const char *jsonstr); const char *jsonstr);
/**
* json_member_direct - start a generic member.
* @js: the json_stream.
* @fieldname: fieldname (if in object), otherwise must be NULL.
* @extra: the space to reserve.
*
* Returns a ptr to @extra bytes.
*/
char *json_member_direct(struct json_stream *js,
const char *fieldname, size_t extra);
/** /**
* json_stream_output - start writing out a json_stream to this conn. * json_stream_output - start writing out a json_stream to this conn.
* @js: the json_stream * @js: the json_stream

View File

@@ -506,9 +506,9 @@ static void json_command_malformed(struct json_connection *jcon,
json_object_start(js, NULL); json_object_start(js, NULL);
json_add_string(js, "jsonrpc", "2.0"); json_add_string(js, "jsonrpc", "2.0");
json_add_literal(js, "id", id, strlen(id)); json_add_primitive(js, "id", id);
json_object_start(js, "error"); json_object_start(js, "error");
json_add_member(js, "code", false, "%" PRIerrcode, JSONRPC2_INVALID_REQUEST); json_add_errcode(js, "code", JSONRPC2_INVALID_REQUEST);
json_add_string(js, "message", error); json_add_string(js, "message", error);
json_object_end(js); json_object_end(js);
json_object_end(js); json_object_end(js);
@@ -578,7 +578,7 @@ static struct json_stream *json_start(struct command *cmd)
json_object_start(js, NULL); json_object_start(js, NULL);
json_add_string(js, "jsonrpc", "2.0"); json_add_string(js, "jsonrpc", "2.0");
json_add_literal(js, "id", cmd->id, strlen(cmd->id)); json_add_jsonstr(js, "id", cmd->id);
return js; return js;
} }
@@ -598,7 +598,7 @@ struct json_stream *json_stream_fail_nodata(struct command *cmd,
assert(code); assert(code);
json_object_start(js, "error"); json_object_start(js, "error");
json_add_member(js, "code", false, "%" PRIerrcode, code); json_add_errcode(js, "code", code);
json_add_string(js, "message", errmsg); json_add_string(js, "message", errmsg);
return js; return js;

View File

@@ -606,8 +606,8 @@ void json_add_opt_log_levels(struct json_stream *response, struct log *log)
struct print_filter *i; struct print_filter *i;
list_for_each(&log->lr->print_filters, i, list) { list_for_each(&log->lr->print_filters, i, list) {
json_add_member(response, "log-level", true, "%s:%s", json_add_str_fmt(response, "log-level", "%s:%s",
log_level_name(i->level), i->prefix); log_level_name(i->level), i->prefix);
} }
} }

View File

@@ -399,7 +399,7 @@ static void sendpay_failure_notification_serialize(struct json_stream *stream,
/* In line with the format of json error returned /* In line with the format of json error returned
* by sendpay_fail(). */ * by sendpay_fail(). */
json_add_member(stream, "code", false, "%" PRIerrcode, pay_errcode); json_add_errcode(stream, "code", pay_errcode);
json_add_string(stream, "message", errmsg); json_add_string(stream, "message", errmsg);
json_object_start(stream, "data"); json_object_start(stream, "data");

View File

@@ -1563,8 +1563,7 @@ static void add_config(struct lightningd *ld,
|| (!streq(buf, "") && strspn(buf, "0123456789.") == strlen(buf))) { || (!streq(buf, "") && strspn(buf, "0123456789.") == strlen(buf))) {
/* Let pure numbers and true/false through as /* Let pure numbers and true/false through as
* literals. */ * literals. */
json_add_literal(response, name0, json_add_primitive(response, name0, buf);
buf, strlen(buf));
return; return;
} }

View File

@@ -32,12 +32,6 @@ void json_add_hex_talarr(struct json_stream *result UNNEEDED,
const char *fieldname UNNEEDED, const char *fieldname UNNEEDED,
const tal_t *data UNNEEDED) const tal_t *data UNNEEDED)
{ fprintf(stderr, "json_add_hex_talarr called!\n"); abort(); } { fprintf(stderr, "json_add_hex_talarr called!\n"); abort(); }
/* Generated stub for json_add_member */
void json_add_member(struct json_stream *js UNNEEDED,
const char *fieldname UNNEEDED,
bool quote UNNEEDED,
const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "json_add_member called!\n"); abort(); }
/* Generated stub for json_add_node_id */ /* Generated stub for json_add_node_id */
void json_add_node_id(struct json_stream *response UNNEEDED, void json_add_node_id(struct json_stream *response UNNEEDED,
const char *fieldname UNNEEDED, const char *fieldname UNNEEDED,
@@ -47,6 +41,11 @@ void json_add_node_id(struct json_stream *response UNNEEDED,
void json_add_num(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED, void json_add_num(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED,
unsigned int value UNNEEDED) unsigned int value UNNEEDED)
{ fprintf(stderr, "json_add_num called!\n"); abort(); } { fprintf(stderr, "json_add_num called!\n"); abort(); }
/* Generated stub for json_add_str_fmt */
void json_add_str_fmt(struct json_stream *js UNNEEDED,
const char *fieldname UNNEEDED,
const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "json_add_str_fmt called!\n"); abort(); }
/* Generated stub for json_add_string */ /* Generated stub for json_add_string */
void json_add_string(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED, const char *value TAKES UNNEEDED) void json_add_string(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED, const char *value TAKES UNNEEDED)
{ fprintf(stderr, "json_add_string called!\n"); abort(); } { fprintf(stderr, "json_add_string called!\n"); abort(); }

View File

@@ -208,7 +208,7 @@ struct json_stream *jsonrpc_stream_fail(struct command *cmd,
struct json_stream *js = jsonrpc_stream_start(cmd); struct json_stream *js = jsonrpc_stream_start(cmd);
json_object_start(js, "error"); json_object_start(js, "error");
json_add_member(js, "code", false, "%d", code); json_add_primitive_fmt(js, "code", "%d", code);
json_add_string(js, "message", err); json_add_string(js, "message", err);
return js; return js;

View File

@@ -634,7 +634,7 @@ static struct command_result *convert_currency(struct command *cmd,
json_add_stringn(req->js, "currency", json_add_stringn(req->js, "currency",
(const char *)ir->offer->currency, (const char *)ir->offer->currency,
tal_bytelen(ir->offer->currency)); tal_bytelen(ir->offer->currency));
json_add_member(req->js, "amount", false, "%f", double_amount); json_add_primitive_fmt(req->js, "amount", "%f", double_amount);
return send_outreq(cmd->plugin, req); return send_outreq(cmd->plugin, req);
} }