mirror of
https://github.com/ElementsProject/lightning.git
synced 2024-11-19 09:54:16 +01:00
json: make json_add_string do partial escapes.
This is useful when we log a JSON-escaped string, so we don't double-escape. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
ed9093fcbd
commit
7ae013202f
@ -4,6 +4,7 @@ LIGHTNING_CLI_OBJS := $(LIGHTNING_CLI_SRC:.c=.o)
|
||||
LIGHTNING_CLI_COMMON_OBJS := \
|
||||
common/configdir.o \
|
||||
common/json.o \
|
||||
common/json_escaped.o \
|
||||
common/version.o
|
||||
|
||||
lightning-cli-all: cli/lightning-cli
|
||||
|
@ -12,6 +12,7 @@ CLI_TEST_COMMON_OBJS := \
|
||||
common/daemon_conn.o \
|
||||
common/htlc_state.o \
|
||||
common/json.o \
|
||||
common/json_escaped.o \
|
||||
common/pseudorand.o \
|
||||
common/memleak.o \
|
||||
common/msg_queue.o \
|
||||
|
@ -409,18 +409,11 @@ void json_add_literal(struct json_result *result, const char *fieldname,
|
||||
|
||||
void json_add_string(struct json_result *result, const char *fieldname, const char *value)
|
||||
{
|
||||
char *escaped = tal_strdup(result, value);
|
||||
size_t i;
|
||||
struct json_escaped *esc = json_partial_escape(NULL, value);
|
||||
|
||||
json_start_member(result, fieldname);
|
||||
for (i = 0; escaped[i]; i++) {
|
||||
/* Replace any funny business. Better safe than accurate! */
|
||||
if (escaped[i] == '\\'
|
||||
|| escaped[i] == '"'
|
||||
|| !cisprint(escaped[i]))
|
||||
escaped[i] = '?';
|
||||
}
|
||||
result_append_fmt(result, "\"%s\"", escaped);
|
||||
result_append_fmt(result, "\"%s\"", esc->s);
|
||||
tal_free(esc);
|
||||
}
|
||||
|
||||
void json_add_bool(struct json_result *result, const char *fieldname, bool value)
|
||||
|
@ -76,7 +76,7 @@ void json_object_end(struct json_result *ptr);
|
||||
struct json_result *new_json_result(const tal_t *ctx);
|
||||
|
||||
/* '"fieldname" : "value"' or '"value"' if fieldname is NULL. Turns
|
||||
* any unusual chars into ?.
|
||||
* any non-printable chars into JSON escapes, but leaves existing escapes alone.
|
||||
*/
|
||||
void json_add_string(struct json_result *result, const char *fieldname, const char *value);
|
||||
|
||||
|
@ -35,7 +35,9 @@ bool json_escaped_eq(const struct json_escaped *a,
|
||||
return streq(a->s, b->s);
|
||||
}
|
||||
|
||||
struct json_escaped *json_escape(const tal_t *ctx, const char *str TAKES)
|
||||
static struct json_escaped *escape(const tal_t *ctx,
|
||||
const char *str TAKES,
|
||||
bool partial)
|
||||
{
|
||||
struct json_escaped *esc;
|
||||
size_t i, n;
|
||||
@ -62,6 +64,31 @@ struct json_escaped *json_escape(const tal_t *ctx, const char *str TAKES)
|
||||
escape = 'r';
|
||||
break;
|
||||
case '\\':
|
||||
if (partial) {
|
||||
/* Don't double-escape standard escapes. */
|
||||
if (str[i+1] == 'n'
|
||||
|| str[i+1] == 'b'
|
||||
|| str[i+1] == 'f'
|
||||
|| str[i+1] == 't'
|
||||
|| str[i+1] == 'r'
|
||||
|| str[i+1] == '/'
|
||||
|| str[i+1] == '\\'
|
||||
|| str[i+1] == '"') {
|
||||
escape = str[i+1];
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
if (str[i+1] == 'u'
|
||||
&& cisxdigit(str[i+2])
|
||||
&& cisxdigit(str[i+3])
|
||||
&& cisxdigit(str[i+4])
|
||||
&& cisxdigit(str[i+5])) {
|
||||
memcpy(esc->s + n, str + i, 6);
|
||||
n += 5;
|
||||
i += 5;
|
||||
continue;
|
||||
}
|
||||
} /* fall thru */
|
||||
case '"':
|
||||
escape = str[i];
|
||||
break;
|
||||
@ -85,6 +112,16 @@ struct json_escaped *json_escape(const tal_t *ctx, const char *str TAKES)
|
||||
return esc;
|
||||
}
|
||||
|
||||
struct json_escaped *json_partial_escape(const tal_t *ctx, const char *str TAKES)
|
||||
{
|
||||
return escape(ctx, str, true);
|
||||
}
|
||||
|
||||
struct json_escaped *json_escape(const tal_t *ctx, const char *str TAKES)
|
||||
{
|
||||
return escape(ctx, str, false);
|
||||
}
|
||||
|
||||
/* By policy, we don't handle \u. Use UTF-8. */
|
||||
const char *json_escaped_unescape(const tal_t *ctx,
|
||||
const struct json_escaped *esc)
|
||||
|
@ -12,6 +12,10 @@ struct json_escaped {
|
||||
/* @str be a valid UTF-8 string */
|
||||
struct json_escaped *json_escape(const tal_t *ctx, const char *str TAKES);
|
||||
|
||||
/* @str is a valid UTF-8 string which may already contain escapes. */
|
||||
struct json_escaped *json_partial_escape(const tal_t *ctx,
|
||||
const char *str TAKES);
|
||||
|
||||
/* Extract a JSON-escaped string. */
|
||||
struct json_escaped *json_tok_escaped_string(const tal_t *ctx,
|
||||
const char *buffer,
|
||||
|
@ -67,12 +67,13 @@ static int test_json_filter(void)
|
||||
x = json_get_member(str, toks, "x");
|
||||
assert(x);
|
||||
assert(x->type == JSMN_STRING);
|
||||
assert((x->end - x->start) == 255);
|
||||
|
||||
/* There are 7 one-letter escapes, and (32-5) \uXXXX escapes. */
|
||||
assert((x->end - x->start) == 255 + 7*1 + (32-5)*5);
|
||||
/* No control characters. */
|
||||
for (i = x->start; i < x->end; i++) {
|
||||
assert(cisprint(str[i]));
|
||||
assert(str[i] != '\\');
|
||||
assert(str[i] != '"');
|
||||
assert(str[i] == '?' || str[i] == badstr[i - x->start]);
|
||||
assert((unsigned)str[i] >= ' ');
|
||||
assert((unsigned)str[i] != 127);
|
||||
}
|
||||
tal_free(result);
|
||||
return 0;
|
||||
@ -112,11 +113,44 @@ static void test_json_escape(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void test_json_partial(void)
|
||||
{
|
||||
const tal_t *ctx = tal(NULL, char);
|
||||
|
||||
assert(streq(json_partial_escape(ctx, "\\")->s, "\\\\"));
|
||||
assert(streq(json_partial_escape(ctx, "\\\\")->s, "\\\\"));
|
||||
assert(streq(json_partial_escape(ctx, "\\\\\\")->s, "\\\\\\\\"));
|
||||
assert(streq(json_partial_escape(ctx, "\\\\\\\\")->s, "\\\\\\\\"));
|
||||
assert(streq(json_partial_escape(ctx, "\\n")->s, "\\n"));
|
||||
assert(streq(json_partial_escape(ctx, "\n")->s, "\\n"));
|
||||
assert(streq(json_partial_escape(ctx, "\\\"")->s, "\\\""));
|
||||
assert(streq(json_partial_escape(ctx, "\"")->s, "\\\""));
|
||||
assert(streq(json_partial_escape(ctx, "\\t")->s, "\\t"));
|
||||
assert(streq(json_partial_escape(ctx, "\t")->s, "\\t"));
|
||||
assert(streq(json_partial_escape(ctx, "\\b")->s, "\\b"));
|
||||
assert(streq(json_partial_escape(ctx, "\b")->s, "\\b"));
|
||||
assert(streq(json_partial_escape(ctx, "\\r")->s, "\\r"));
|
||||
assert(streq(json_partial_escape(ctx, "\r")->s, "\\r"));
|
||||
assert(streq(json_partial_escape(ctx, "\\f")->s, "\\f"));
|
||||
assert(streq(json_partial_escape(ctx, "\f")->s, "\\f"));
|
||||
/* You're allowed to escape / according to json.org. */
|
||||
assert(streq(json_partial_escape(ctx, "\\/")->s, "\\/"));
|
||||
assert(streq(json_partial_escape(ctx, "/")->s, "/"));
|
||||
|
||||
assert(streq(json_partial_escape(ctx, "\\u0FFF")->s, "\\u0FFF"));
|
||||
assert(streq(json_partial_escape(ctx, "\\u0FFFx")->s, "\\u0FFFx"));
|
||||
|
||||
/* Unknown escapes should be escaped. */
|
||||
assert(streq(json_partial_escape(ctx, "\\x")->s, "\\\\x"));
|
||||
tal_free(ctx);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_json_tok_bitcoin_amount();
|
||||
test_json_filter();
|
||||
test_json_escape();
|
||||
test_json_partial();
|
||||
assert(!taken_any());
|
||||
take_cleanup();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user