Browse Source

ccan: import ccan/json_out and ccan/json_escape.

These are generalized from our internal implementations.

The main difference is that 'struct json_escaped' is now 'struct
json_escape', so we replace that immediately.

The difference between lightningd's json-writing ringbuffer and the
more generic ccan/json_out is that the latter has a better API and
handles escaping transparently if something slips through (though
it does offer direct accessors so you can mess things up yourself!).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
pull/2938/head
Rusty Russell 5 years ago
parent
commit
220449e1cd
  1. 10
      Makefile
  2. 1
      ccan/ccan/json_escape/LICENSE
  3. 39
      ccan/ccan/json_escape/_info
  4. 73
      ccan/ccan/json_escape/json_escape.c
  5. 44
      ccan/ccan/json_escape/json_escape.h
  6. 41
      ccan/ccan/json_escape/test/run-partial.c
  7. 35
      ccan/ccan/json_escape/test/run-take.c
  8. 44
      ccan/ccan/json_escape/test/run.c
  9. 1
      ccan/ccan/json_out/LICENSE
  10. 82
      ccan/ccan/json_out/_info
  11. 356
      ccan/ccan/json_out/json_out.c
  12. 200
      ccan/ccan/json_out/json_out.h
  13. 2
      ccan/ccan/json_out/test/run-debugging.c
  14. 48
      ccan/ccan/json_out/test/run-move_cb.c
  15. 141
      ccan/ccan/json_out/test/run.c
  16. 1
      cli/Makefile
  17. 2
      cli/lightning-cli.c
  18. 1
      cli/test/Makefile
  19. 1
      common/Makefile
  20. 35
      common/json_escaped.h
  21. 15
      common/json_tok.c
  22. 4
      common/json_tok.h
  23. 46
      common/test/run-json_escaped.c
  24. 7
      common/test/run-param.c
  25. 1
      lightningd/Makefile
  26. 4
      lightningd/gossip_control.c
  27. 16
      lightningd/invoice.c
  28. 6
      lightningd/json.c
  29. 4
      lightningd/json.h
  30. 6
      lightningd/jsonrpc.c
  31. 2
      lightningd/lightningd.c
  32. 4
      lightningd/options.c
  33. 1
      lightningd/peer_htlcs.c
  34. 1
      lightningd/test/Makefile
  35. 8
      lightningd/test/run-invoice-select-inchan.c
  36. 2
      lightningd/test/run-jsonrpc.c
  37. 1
      plugins/Makefile
  38. 16
      wallet/db.c
  39. 8
      wallet/db.h
  40. 10
      wallet/invoices.c
  41. 6
      wallet/invoices.h
  42. 4
      wallet/test/run-db.c
  43. 8
      wallet/test/run-wallet.c
  44. 4
      wallet/wallet.c
  45. 6
      wallet/wallet.h

10
Makefile

@ -31,7 +31,7 @@ SANITIZER_FLAGS=
endif
ifeq ($(DEVELOPER),1)
DEV_CFLAGS=-DCCAN_TAKE_DEBUG=1 -DCCAN_TAL_DEBUG=1
DEV_CFLAGS=-DCCAN_TAKE_DEBUG=1 -DCCAN_TAL_DEBUG=1 -DCCAN_JSON_OUT_DEBUG=1
else
DEV_CFLAGS=
endif
@ -81,6 +81,8 @@ CCAN_OBJS := \
ccan-io-fdpass.o \
ccan-isaac.o \
ccan-isaac64.o \
ccan-json_escape.o \
ccan-json_out.o \
ccan-list.o \
ccan-mem.o \
ccan-membuf.o \
@ -144,6 +146,8 @@ CCAN_HEADERS := \
$(CCANDIR)/ccan/io/io_plan.h \
$(CCANDIR)/ccan/isaac/isaac.h \
$(CCANDIR)/ccan/isaac/isaac64.h \
$(CCANDIR)/ccan/json_escape/json_escape.h \
$(CCANDIR)/ccan/json_out/json_out.h \
$(CCANDIR)/ccan/likely/likely.h \
$(CCANDIR)/ccan/list/list.h \
$(CCANDIR)/ccan/mem/mem.h \
@ -657,3 +661,7 @@ ccan-bitmap.o: $(CCANDIR)/ccan/bitmap/bitmap.c
$(CC) $(CFLAGS) -c -o $@ $<
ccan-membuf.o: $(CCANDIR)/ccan/membuf/membuf.c
$(CC) $(CFLAGS) -c -o $@ $<
ccan-json_escape.o: $(CCANDIR)/ccan/json_escape/json_escape.c
$(CC) $(CFLAGS) -c -o $@ $<
ccan-json_out.o: $(CCANDIR)/ccan/json_out/json_out.c
$(CC) $(CFLAGS) -c -o $@ $<

1
ccan/ccan/json_escape/LICENSE

@ -0,0 +1 @@
../../licenses/BSD-MIT

39
ccan/ccan/json_escape/_info

@ -0,0 +1,39 @@
#include "config.h"
#include <stdio.h>
#include <string.h>
/**
* json_escape - Escape sequences for JSON strings
*
* This code helps you format strings into forms useful for JSON.
*
* Author: Rusty Russell <rusty@rustcorp.com.au>
* License: BSD-MIT
* Example:
* // Print arguments as a JSON array.
* #include <ccan/json_escape/json_escape.h>
*
* int main(int argc, char *argv[])
* {
* printf("[");
* for (int i = 1; i < argc; i++) {
* struct json_escape *e = json_escape(NULL, argv[i]);
* printf("%s\"%s\"", i == 1 ? "" : ",", e->s);
* }
* printf("]\n");
* return 0;
* }
*/
int main(int argc, char *argv[])
{
/* Expect exactly one argument */
if (argc != 2)
return 1;
if (strcmp(argv[1], "depends") == 0) {
printf("ccan/tal\n");
return 0;
}
return 1;
}

73
common/json_escaped.c → ccan/ccan/json_escape/json_escape.c

@ -1,46 +1,58 @@
#include <common/json_escaped.h>
/* MIT (BSD) license - see LICENSE file for details */
#include <ccan/json_escape/json_escape.h>
#include <stdio.h>
struct json_escaped *json_escaped_string_(const tal_t *ctx,
const void *bytes, size_t len)
struct json_escape *json_escape_string_(const tal_t *ctx,
const void *bytes, size_t len)
{
struct json_escaped *esc;
struct json_escape *esc;
esc = (void *)tal_arr_label(ctx, char, len + 1,
TAL_LABEL(struct json_escaped, ""));
TAL_LABEL(struct json_escape, ""));
memcpy(esc->s, bytes, len);
esc->s[len] = '\0';
return esc;
}
struct json_escaped *json_to_escaped_string(const tal_t *ctx,
const char *buffer,
const jsmntok_t *tok)
bool json_escape_eq(const struct json_escape *a, const struct json_escape *b)
{
if (tok->type != JSMN_STRING)
return NULL;
/* jsmn always gives us ~ well-formed strings. */
return json_escaped_string_(ctx, buffer + tok->start,
tok->end - tok->start);
return streq(a->s, b->s);
}
bool json_escaped_eq(const struct json_escaped *a,
const struct json_escaped *b)
bool json_escape_needed(const char *str, size_t len)
{
return streq(a->s, b->s);
for (size_t i = 0; i < len; i++) {
if ((unsigned)str[i] < ' '
|| str[i] == 127
|| str[i] == '"'
|| str[i] == '\\')
return true;
}
return false;
}
static struct json_escaped *escape(const tal_t *ctx,
const char *str TAKES,
bool partial)
static struct json_escape *escape(const tal_t *ctx,
const char *str TAKES,
size_t len,
bool partial)
{
struct json_escaped *esc;
struct json_escape *esc;
size_t i, n;
/* Fast path: can steal, and nothing to escape. */
if (is_taken(str)
&& tal_count(str) > len
&& !json_escape_needed(str, len)) {
taken(str);
esc = (struct json_escape *)tal_steal(ctx, str);
esc->s[len] = '\0';
return esc;
}
/* Worst case: all \uXXXX */
esc = (struct json_escaped *)tal_arr(ctx, char, strlen(str) * 6 + 1);
esc = (struct json_escape *)tal_arr(ctx, char, len * 6 + 1);
for (i = n = 0; str[i]; i++, n++) {
for (i = n = 0; i < len; i++, n++) {
char escape = 0;
switch (str[i]) {
case '\n':
@ -107,19 +119,24 @@ static struct json_escaped *escape(const tal_t *ctx,
return esc;
}
struct json_escaped *json_partial_escape(const tal_t *ctx, const char *str TAKES)
struct json_escape *json_partial_escape(const tal_t *ctx, const char *str TAKES)
{
return escape(ctx, str, strlen(str), true);
}
struct json_escape *json_escape(const tal_t *ctx, const char *str TAKES)
{
return escape(ctx, str, true);
return escape(ctx, str, strlen(str), false);
}
struct json_escaped *json_escape(const tal_t *ctx, const char *str TAKES)
struct json_escape *json_escape_len(const tal_t *ctx, const char *str TAKES,
size_t len)
{
return escape(ctx, str, false);
return escape(ctx, str, len, 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)
const char *json_escape_unescape(const tal_t *ctx, const struct json_escape *esc)
{
char *unesc = tal_arr(ctx, char, strlen(esc->s) + 1);
size_t i, n;

44
ccan/ccan/json_escape/json_escape.h

@ -0,0 +1,44 @@
/* MIT (BSD) license - see LICENSE file for details */
#ifndef CCAN_JSON_ESCAPE_H
#define CCAN_JSON_ESCAPE_H
#include "config.h"
#include <ccan/tal/tal.h>
/* Type differentiation for a correctly-escaped JSON string */
struct json_escape {
/* NUL terminated string. */
char s[1];
};
/**
* json_escape - escape a valid UTF-8 string.
* @ctx: tal context to allocate from.
* @str: the string to escape.
*
* Allocates and returns a valid JSON string (without surrounding quotes).
*/
struct json_escape *json_escape(const tal_t *ctx, const char *str TAKES);
/* Version with @len */
struct json_escape *json_escape_len(const tal_t *ctx,
const char *str TAKES, size_t len);
/* @str is a valid UTF-8 string which may already contain escapes. */
struct json_escape *json_partial_escape(const tal_t *ctx,
const char *str TAKES);
/* Do we need to escape this str? */
bool json_escape_needed(const char *str, size_t len);
/* Are two escape json strings identical? */
bool json_escape_eq(const struct json_escape *a,
const struct json_escape *b);
/* Internal routine for creating json_escape from bytes. */
struct json_escape *json_escape_string_(const tal_t *ctx,
const void *bytes, size_t len);
/* Be very careful here! Can fail! Doesn't handle \u: use UTF-8 please. */
const char *json_escape_unescape(const tal_t *ctx,
const struct json_escape *esc);
#endif /* CCAN_JSON_ESCAPE_H */

41
ccan/ccan/json_escape/test/run-partial.c

@ -0,0 +1,41 @@
#include <ccan/json_escape/json_escape.h>
/* Include the C files directly. */
#include <ccan/json_escape/json_escape.c>
#include <ccan/tap/tap.h>
int main(void)
{
const tal_t *ctx = tal(NULL, char);
/* This is how many tests you plan to run */
plan_tests(21);
ok1(!strcmp(json_partial_escape(ctx, "\\")->s, "\\\\"));
ok1(!strcmp(json_partial_escape(ctx, "\\\\")->s, "\\\\"));
ok1(!strcmp(json_partial_escape(ctx, "\\\\\\")->s, "\\\\\\\\"));
ok1(!strcmp(json_partial_escape(ctx, "\\\\\\\\")->s, "\\\\\\\\"));
ok1(!strcmp(json_partial_escape(ctx, "\\n")->s, "\\n"));
ok1(!strcmp(json_partial_escape(ctx, "\n")->s, "\\n"));
ok1(!strcmp(json_partial_escape(ctx, "\\\"")->s, "\\\""));
ok1(!strcmp(json_partial_escape(ctx, "\"")->s, "\\\""));
ok1(!strcmp(json_partial_escape(ctx, "\\t")->s, "\\t"));
ok1(!strcmp(json_partial_escape(ctx, "\t")->s, "\\t"));
ok1(!strcmp(json_partial_escape(ctx, "\\b")->s, "\\b"));
ok1(!strcmp(json_partial_escape(ctx, "\b")->s, "\\b"));
ok1(!strcmp(json_partial_escape(ctx, "\\r")->s, "\\r"));
ok1(!strcmp(json_partial_escape(ctx, "\r")->s, "\\r"));
ok1(!strcmp(json_partial_escape(ctx, "\\f")->s, "\\f"));
ok1(!strcmp(json_partial_escape(ctx, "\f")->s, "\\f"));
/* You're allowed to escape / according to json.org. */
ok1(!strcmp(json_partial_escape(ctx, "\\/")->s, "\\/"));
ok1(!strcmp(json_partial_escape(ctx, "/")->s, "/"));
ok1(!strcmp(json_partial_escape(ctx, "\\u0FFF")->s, "\\u0FFF"));
ok1(!strcmp(json_partial_escape(ctx, "\\u0FFFx")->s, "\\u0FFFx"));
/* Unknown escapes should be escaped. */
ok1(!strcmp(json_partial_escape(ctx, "\\x")->s, "\\\\x"));
tal_free(ctx);
return 0;
}

35
ccan/ccan/json_escape/test/run-take.c

@ -0,0 +1,35 @@
#include <ccan/json_escape/json_escape.h>
/* Include the C files directly. */
#include <ccan/json_escape/json_escape.c>
#include <ccan/tap/tap.h>
int main(void)
{
const tal_t *ctx = tal(NULL, char);
struct json_escape *e;
char *p;
/* This is how many tests you plan to run */
plan_tests(5);
/* This should simply be tal_steal */
p = tal_dup_arr(NULL, char, "Hello", 6, 0);
e = json_escape(ctx, take(p));
ok1(!strcmp(e->s, "Hello"));
ok1((void *)e == (void *)p);
ok1(tal_parent(e) == ctx);
/* This can't be tal_steal, but still should be freed. */
p = tal_dup_arr(NULL, char,
"\\\b\f\n\r\t\""
"\\\\\\b\\f\\n\\r\\t\\\"", 22, 0);
e = json_escape(ctx, take(p));
ok1(tal_parent(e) == ctx);
ok1(!strcmp(e->s,
"\\\\\\b\\f\\n\\r\\t\\\""
"\\\\\\\\\\\\b\\\\f\\\\n\\\\r\\\\t\\\\\\\""));
tal_free(ctx);
/* This exits depending on whether all tests passed */
return exit_status();
}

44
ccan/ccan/json_escape/test/run.c

@ -0,0 +1,44 @@
#include <ccan/json_escape/json_escape.h>
/* Include the C files directly. */
#include <ccan/json_escape/json_escape.c>
#include <ccan/tap/tap.h>
int main(void)
{
const tal_t *ctx = tal(NULL, char);
struct json_escape *e;
/* This is how many tests you plan to run */
plan_tests(6);
e = json_escape(ctx, "Hello");
ok1(!strcmp(e->s, "Hello"));
ok1(!strcmp(json_escape_unescape(ctx, e),
"Hello"));
e = json_escape(ctx,
"\\\b\f\n\r\t\""
"\\\\\\b\\f\\n\\r\\t\\\"");
ok1(!strcmp(e->s,
"\\\\\\b\\f\\n\\r\\t\\\""
"\\\\\\\\\\\\b\\\\f\\\\n\\\\r\\\\t\\\\\\\""));
ok1(!strcmp(json_escape_unescape(ctx, e),
"\\\b\f\n\r\t\""
"\\\\\\b\\f\\n\\r\\t\\\""));
/* This one doesn't escape the already-escaped chars */
e = json_partial_escape(ctx,
"\\\b\f\n\r\t\""
"\\\\\\b\\f\\n\\r\\t\\\"");
ok1(!strcmp(e->s,
"\\\\\\b\\f\\n\\r\\t\\\""
"\\\\\\b\\f\\n\\r\\t\\\""));
ok1(!strcmp(json_escape_unescape(ctx, e),
"\\\b\f\n\r\t\""
"\\\b\f\n\r\t\""));
tal_free(ctx);
/* This exits depending on whether all tests passed */
return exit_status();
}

1
ccan/ccan/json_out/LICENSE

@ -0,0 +1 @@
../../licenses/BSD-MIT

82
ccan/ccan/json_out/_info

@ -0,0 +1,82 @@
#include "config.h"
#include <stdio.h>
#include <string.h>
/**
* json_out - Code for creating simple JSON output.
*
* This code helps you create well-formed JSON strings.
*
* Author: Rusty Russell <rusty@rustcorp.com.au>
* License: BSD-MIT
*
* Example:
* // Given "a 1 true" outputs {"argv1":"a","argv2":1,"argv3":true}
* // Print arguments as a JSON array.
* #include <ccan/json_out/json_out.h>
* #include <stdio.h>
* #include <string.h>
* #include <unistd.h>
*
* // Simplistic test to see if str needs quotes.
* static bool can_be_json_literal(const char *str)
* {
* char *endp;
* if (strtol(str, &endp, 10) != LONG_MIN
* && endp != str
* && *endp == '\0')
* return true;
* return !strcmp(str, "true")
* || !strcmp(str, "false")
* || !strcmp(str, "null");
* }
*
* int main(int argc, char *argv[])
* {
* struct json_out *jout = json_out_new(NULL);
* size_t len;
* const char *p;
*
* json_out_start(jout, NULL, '{');
* for (int i = 1; i < argc; i++) {
* char fieldname[80];
* sprintf(fieldname, "argv%i", i);
* json_out_add(jout, fieldname,
* !can_be_json_literal(argv[i]),
* "%s", argv[i]);
* }
* json_out_end(jout, '}');
* // Force appending of \n
* json_out_direct(jout, 1)[0] = '\n';
* json_out_finished(jout);
*
* // Now write it out.
* while ((p = json_out_contents(jout, &len)) != NULL) {
* int i = write(STDOUT_FILENO, p, len);
* if (i <= 0)
* exit(1);
* json_out_consume(jout, i);
* }
*
* tal_free(jout);
* return 0;
* }
*
*/
int main(int argc, char *argv[])
{
/* Expect exactly one argument */
if (argc != 2)
return 1;
if (strcmp(argv[1], "depends") == 0) {
printf("ccan/compiler\n");
printf("ccan/json_escape\n");
printf("ccan/membuf\n");
printf("ccan/tal\n");
printf("ccan/typesafe_cb\n");
return 0;
}
return 1;
}

356
ccan/ccan/json_out/json_out.c

@ -0,0 +1,356 @@
/* MIT (BSD) license - see LICENSE file for details */
#include <ccan/json_escape/json_escape.h>
#include <ccan/json_out/json_out.h>
#include <ccan/membuf/membuf.h>
#include <stdarg.h>
#include <stdio.h>
struct json_out {
/* Callback if we reallocate. */
void (*move_cb)(struct json_out *jout, ptrdiff_t delta, void *arg);
void *cb_arg;
#ifdef CCAN_JSON_OUT_DEBUG
/* tal_arr of types ( or [ we're enclosed in. NULL if oom. */
char *wrapping;
#endif
/* True if we haven't yet put an element in current wrapping */
bool empty;
/* Output. */
MEMBUF(char) outbuf;
};
/* Realloc helper for tal membufs */
static void *membuf_tal_realloc(struct membuf *mb,
void *rawelems, size_t newsize)
{
char *p = rawelems;
if (!tal_resize(&p, newsize))
return NULL;
return p;
}
struct json_out *json_out_new(const tal_t *ctx)
{
struct json_out *jout = tal(ctx, struct json_out);
char *pool;
if (!jout)
return NULL;
pool = tal_arr(jout, char, 64);
if (!pool)
return tal_free(jout);
membuf_init(&jout->outbuf, pool, tal_count(pool), membuf_tal_realloc);
#ifdef CCAN_JSON_OUT_DEBUG
jout->wrapping = tal_arr(jout, char, 0);
#endif
jout->empty = true;
jout->move_cb = NULL;
return jout;
}
void json_out_call_on_move_(struct json_out *jout,
void (*cb)(struct json_out *jout, ptrdiff_t delta,
void *arg),
void *arg)
{
if (cb)
assert(!jout->move_cb);
jout->move_cb = cb;
jout->cb_arg = arg;
}
struct json_out *json_out_dup(const tal_t *ctx, const struct json_out *src)
{
size_t num_elems = membuf_num_elems(&src->outbuf);
char *elems = membuf_elems(&src->outbuf);
struct json_out *jout = tal_dup(ctx, struct json_out, src);
char *pool;
if (!jout)
return NULL;
pool = tal_dup_arr(jout, char, elems, num_elems, 0);
if (!pool)
return tal_free(jout);
membuf_init(&jout->outbuf, pool, num_elems, membuf_tal_realloc);
membuf_added(&jout->outbuf, num_elems);
#ifdef CCAN_JSON_OUT_DEBUG
jout->wrapping = tal_dup_arr(jout, char,
jout->wrapping, tal_count(jout->wrapping),
0);
#endif
return jout;
}
static void indent(struct json_out *jout, char type)
{
#ifdef CCAN_JSON_OUT_DEBUG
/* Can't check if we ran out of memory. */
if (jout->wrapping) {
size_t n = tal_count(jout->wrapping);
if (!tal_resize(&jout->wrapping, n+1))
jout->wrapping = tal_free(jout->wrapping);
else
jout->wrapping[n] = type;
}
#endif
jout->empty = true;
}
static void unindent(struct json_out *jout, char type)
{
#ifdef CCAN_JSON_OUT_DEBUG
/* Can't check if we ran out of memory. */
if (jout->wrapping) {
size_t indent = tal_count(jout->wrapping);
assert(indent > 0);
/* Both [ and ] and { and } are two apart in ASCII */
assert(jout->wrapping[indent-1] == type - 2);
tal_resize(&jout->wrapping, indent-1);
}
#endif
jout->empty = false;
}
/* Make sure jout->outbuf has room for len: return pointer */
static char *mkroom(struct json_out *jout, size_t len)
{
ptrdiff_t delta = membuf_prepare_space(&jout->outbuf, len);
if (delta && jout->move_cb)
jout->move_cb(jout, delta, jout->cb_arg);
return membuf_space(&jout->outbuf);
}
static void check_fieldname(const struct json_out *jout,
const char *fieldname)
{
#ifdef CCAN_JSON_OUT_DEBUG
/* We don't escape this for you */
assert(!fieldname || !json_escape_needed(fieldname, strlen(fieldname)));
/* Can't check anything else if we ran out of memory. */
if (jout->wrapping) {
size_t n = tal_count(jout->wrapping);
if (n == 0)
/* Can't have a fieldname if not in anything! */
assert(!fieldname);
else if (jout->wrapping[n-1] == '[')
/* No fieldnames in arrays. */
assert(!fieldname);
else {
/* Must have fieldnames in objects. */
assert(fieldname);
}
}
#endif
}
char *json_out_member_direct(struct json_out *jout,
const char *fieldname, size_t extra)
{
char *dest;
/* Prepend comma if required. */
if (!jout->empty)
extra++;
check_fieldname(jout, fieldname);
if (fieldname)
extra += 1 + strlen(fieldname) + 2;
dest = mkroom(jout, extra);
if (!dest)
goto out;
if (!jout->empty)
*(dest++) = ',';
if (fieldname) {
*(dest++) = '"';
memcpy(dest, fieldname, strlen(fieldname));
dest += strlen(fieldname);
*(dest++) = '"';
*(dest++) = ':';
}
membuf_added(&jout->outbuf, extra);
out:
jout->empty = false;
return dest;
}
bool json_out_start(struct json_out *jout, const char *fieldname, char type)
{
char *p;
assert(type == '[' || type == '{');
p = json_out_member_direct(jout, fieldname, 1);
if (p)
p[0] = type;
indent(jout, type);
return p != NULL;
}
bool json_out_end(struct json_out *jout, char type)
{
char *p;
assert(type == '}' || type == ']');
p = json_out_direct(jout, 1);
if (p)
p[0] = type;
unindent(jout, type);
return p != NULL;
}
bool json_out_addv(struct json_out *jout,
const char *fieldname,
bool quote,
const char *fmt,
va_list ap)
{
size_t fmtlen, avail;
va_list ap2;
char *dst;
if (!json_out_member_direct(jout, fieldname, 0))
return false;
/* Make a copy in case we need it below. */
va_copy(ap2, ap);
/* We can use any additional space, but need room for ". */
avail = membuf_num_space(&jout->outbuf);
if (quote) {
if (avail < 2)
avail = 0;
else
avail -= 2;
}
/* Try printing in place first. */
dst = membuf_space(&jout->outbuf);
fmtlen = vsnprintf(dst + quote, avail, fmt, ap);
/* Horrible subtlety: vsnprintf *will* NUL terminate, even if it means
* chopping off the last character. So if fmtlen ==
* membuf_num_space(&jout->outbuf), the result was truncated! */
if (fmtlen + (int)quote*2 >= membuf_num_space(&jout->outbuf)) {
/* Make room for NUL terminator, even though we don't want it */
dst = mkroom(jout, fmtlen + 1 + (int)quote*2);
if (!dst)
goto out;
vsprintf(dst + quote, fmt, ap2);
}
#ifdef CCAN_JSON_OUT_DEBUG
/* You're not inserting junk here, are you? */
assert(quote || !json_escape_needed(dst, fmtlen));
#endif
/* Of course, if we need to escape it, we have to redo it all. */
if (quote) {
if (json_escape_needed(dst + quote, fmtlen)) {
struct json_escape *e;
e = json_escape_len(NULL, dst + quote, fmtlen);
fmtlen = strlen(e->s);
dst = mkroom(jout, fmtlen + (int)quote*2);
if (!dst)
goto out;
memcpy(dst + quote, e, fmtlen);
tal_free(e);
}
dst[0] = '"';
dst[fmtlen+1] = '"';
}
membuf_added(&jout->outbuf, fmtlen + (int)quote*2);
out:
va_end(ap2);
return dst != NULL;
}
bool json_out_add(struct json_out *jout,
const char *fieldname,
bool quote,
const char *fmt, ...)
{
va_list ap;
bool ret;
va_start(ap, fmt);
ret = json_out_addv(jout, fieldname, quote, fmt, ap);
va_end(ap);
return ret;
}
bool json_out_addstr(struct json_out *jout,
const char *fieldname,
const char *str)
{
size_t len = strlen(str);
char *p;
struct json_escape *e;
if (json_escape_needed(str, len)) {
e = json_escape(NULL, str);
str = e->s;
len = strlen(str);
} else
e = NULL;
p = json_out_member_direct(jout, fieldname, len + 2);
if (p) {
p[0] = p[1+len] = '"';
memcpy(p+1, str, len);
}
tal_free(e);
return p != NULL;
}
bool json_out_add_splice(struct json_out *jout,
const char *fieldname,
const struct json_out *src)
{
const char *p;
size_t len;
p = json_out_contents(src, &len);
if (!p)
return false;
memcpy(json_out_member_direct(jout, fieldname, len), p, len);
return true;
}
char *json_out_direct(struct json_out *jout, size_t len)
{
char *p = mkroom(jout, len);
if (p)
membuf_added(&jout->outbuf, len);
return p;
}
void json_out_finished(const struct json_out *jout)
{
#ifdef CCAN_JSON_OUT_DEBUG
assert(tal_count(jout->wrapping) == 0);
#endif
}
const char *json_out_contents(const struct json_out *jout, size_t *len)
{
*len = membuf_num_elems(&jout->outbuf);
return *len ? membuf_elems(&jout->outbuf) : NULL;
}
void json_out_consume(struct json_out *jout, size_t len)
{
membuf_consume(&jout->outbuf, len);
}

200
ccan/ccan/json_out/json_out.h

@ -0,0 +1,200 @@
/* MIT (BSD) license - see LICENSE file for details */
#ifndef CCAN_JSON_OUT_H
#define CCAN_JSON_OUT_H
#include <ccan/compiler/compiler.h>
#include <ccan/tal/tal.h>
#include <ccan/typesafe_cb/typesafe_cb.h>
#include <stddef.h>
struct json_out;
/**
* json_out_new - allocate a json_out stream.
* @ctx: the tal_context to allocate from, or NULL
*
* Returns NULL if tal allocation fails.
*/
struct json_out *json_out_new(const tal_t *ctx);
/**
* json_out_call_on_move - callback for when buffer is reallocated.
* @jout: the json_out object to attach to.
* @cb: the callback to call.
* @arg: the argument to @cb (must match type).
*
* A NULL @cb disables. You can't currently have more than one callback.
* The @delta argument to @cb is the difference between the old location
* and the new one, and is never zero.
*/
#define json_out_call_on_move(jout, cb, arg) \
json_out_call_on_move_((jout), \
typesafe_cb_preargs(void, void *, \
(cb), (arg), \
struct json_out *, \
ptrdiff_t), \
(arg))
void json_out_call_on_move_(struct json_out *jout,
void (*cb)(struct json_out *jout, ptrdiff_t delta,
void *arg),
void *arg);
/**
* json_out_dup - duplicate a json_out stream.
* @ctx: the tal_context to allocate from, or NULL
* @src: the json_out to copy.
*/
struct json_out *json_out_dup(const tal_t *ctx, const struct json_out *src);
/**
* json_out_start - start an array or object.
* @jout: the json_out object to write into.
* @fieldname: the fieldname, if inside an object, or NULL if inside an array.
* @type: '[' or '{' to start an array or object, respectively.
*
* Returns true unless tal_resize() fails.
* Literally writes '"@fieldname": @type' or '@type ' if fieldname is NULL.
* @fieldname must not need JSON escaping.
*/
bool json_out_start(struct json_out *jout, const char *fieldname, char type);
/**
* json_out_end - end an array or object.
* @jout: the json_out object to write into.
* @type: '}' or ']' to end an array or object, respectively.
*
* Returns true unless tal_resize() fails.
*
* Literally writes ']' or '}', keeping track of whether we need to append
* a comma.
*/
bool json_out_end(struct json_out *jout, char type);
/**
* json_out_add - add a formatted member.
* @jout: the json_out object to write into.
* @fieldname: optional fieldname to prepend (must not need escaping).
* @quote: if true, surround fmt by " and ".
* @fmt...: the printf-style format
*
* Returns true unless tal_resize() fails.
*
* If you're in an array, @fieldname must be NULL. If you're in an
* object, @fieldname must be non-NULL. This is checked if
* CCAN_JSON_OUT_DEBUG is defined.
* @fieldname must not need JSON escaping.
*
* If the resulting string requires escaping, and @quote is true, we
* call json_escape().
*/
PRINTF_FMT(4,5)
bool json_out_add(struct json_out *jout,
const char *fieldname,
bool quote,
const char *fmt, ...);
/**
* json_out_addv - add a formatted member (vararg variant)
* @jout: the json_out object to write into.
* @fieldname: optional fieldname to prepend.
* @quote: if true, surround fmt by " and ".
* @fmt: the printf-style format
* @ap: the argument list.
*
* See json_out_add() above.
*/
bool json_out_addv(struct json_out *jout,
const char *fieldname,
bool quote,
const char *fmt,
va_list ap);
/**
* json_out_addstr - convenience helper to add a string field.
* @jout: the json_out object to write into.
* @fieldname: optional fieldname to prepend.
* @str: the string to add (must not be NULL).
*
* Equivalent to json_out_add(@jout, @fieldname, true, "%s", @str);
*/
bool json_out_addstr(struct json_out *jout,
const char *fieldname,
const char *str);
/**
* json_out_member_direct - add a field, with direct access.
* @jout: the json_out object to write into.
* @fieldname: optional fieldname to prepend.
* @extra: how many bytes to allocate.
*
* @fieldname must not need JSON escaping. Returns a direct pointer into
* the @extra bytes, or NULL if tal_resize() fails.
*
* This allows you to write your own efficient type-specific helpers.
*/
char *json_out_member_direct(struct json_out *jout,
const char *fieldname, size_t extra);
/**
* json_out_direct - make room in output and access directly.
* @jout: the json_out object to write into.
* @len: the length to allocate.
*
* This lets you access the json_out stream directly, to save a copy,
* if you know exactly how much you will write.
*
* Returns a pointer to @len bytes at the end of @jout, or NULL if
* tal_resize() fails.
*
* This is dangerous, since it doesn't automatically prepend a ","
* like the internal logic does, but can be used (carefully) to add
* entire objects, or whitespace.
*/
char *json_out_direct(struct json_out *jout, size_t extra);
/**
* json_out_add_splice - copy a field from another json_out.
* @jout: the json_out object to write into.
* @fieldname: optional fieldname to prepend.
* @src: the json_out object to copy from.
*
* This asserts that @src is well-formed (as per json_out_finished()),
* then places it into @jout with optional @fieldname prepended. This
* can be used to assemble sub-objects for your JSON and then copy
* them in.
*
* Note that it will call json_out_contents(@src), so it expects that
* object to be unconsumed.
*
* Returns false if tal_resize() fails.
*/
bool json_out_add_splice(struct json_out *jout,
const char *fieldname,
const struct json_out *src);
/**
* json_out_finished - assert that the json buffer is finished.
* @jout: the json_out object written to.
*
* This simply causes internal assertions that all arrays and objects are
* finished. It needs CCAN_JSON_OUT_DEBUG defined to have any effect.
*/
void json_out_finished(const struct json_out *jout);
/**
* json_out_contents - read contents from json_out stream.
* @jout: the json_out object we want to read from.
* @len: set to the length of the buffer returned.
*
* This returns a pointer into the JSON written so far. Returns NULL
* and sets @len to 0 if there's nothing left in the buffer.
*/
const char *json_out_contents(const struct json_out *jout, size_t *len);
/**
* json_out_consume - discard contents from json_out stream.
* @jout: the json_out object we read from.
* @len: the length to consume (must be <= @len from json_out_contents)
*/
void json_out_consume(struct json_out *jout, size_t len);
#endif /* CCAN_JSON_OUT_H */

2
ccan/ccan/json_out/test/run-debugging.c

@ -0,0 +1,2 @@
#define CCAN_JSON_OUT_DEBUG 1
#include "run.c"

48
ccan/ccan/json_out/test/run-move_cb.c

@ -0,0 +1,48 @@
#include <ccan/json_out/json_out.h>
/* Include the C files directly. */
#include <ccan/json_out/json_out.c>
#include <ccan/tap/tap.h>
static const char *ptr;
static bool called = false;
static void move_cb(struct json_out *jout, ptrdiff_t delta,
struct json_out *arg)
{
ptr += delta;
called = true;
ok1(arg == jout);
}
int main(void)
{
const tal_t *ctx = tal(NULL, char);
struct json_out *jout;
char *p;
size_t len;
/* This is how many tests you plan to run */
plan_tests(3);
/* Test nested arrays. */
jout = json_out_new(ctx);
json_out_call_on_move(jout, move_cb, jout);
json_out_start(jout, NULL, '{');
ptr = json_out_contents(jout, &len);
p = json_out_member_direct(jout, "fieldname", 102);
p[0] = '"';
p[101] = '"';
memset(p+1, 'p', 100);
json_out_finished(jout);
ok1(called);
/* Contents should have moved correctly. */
ok1(json_out_contents(jout, &len) == ptr);
tal_free(ctx);
/* This exits depending on whether all tests passed */
return exit_status();
}

141
ccan/ccan/json_out/test/run.c

@ -0,0 +1,141 @@
#include <ccan/json_out/json_out.h>
/* Include the C files directly. */
#include <ccan/json_out/json_out.c>
#include <ccan/tap/tap.h>
static void test_json_out_add(const tal_t *ctx,
char c, bool quote, const char *escaped)
{
/* 64 is the size of the initial buf, so we test that. */
for (size_t i = 1; i < 64; i++) {
struct json_out *jout;
char str[64 + 1];
const char *r;
size_t len;
char fieldname[64 + 1];
jout = json_out_new(ctx);
json_out_start(jout, NULL, '{');
memset(str, c, i);
str[i] = '\0';
memset(fieldname, 'f', i);
fieldname[i] = '\0';
json_out_add(jout, fieldname, quote, "%s", str);
json_out_end(jout, '}');
json_out_finished(jout);
r = json_out_contents(jout, &len);
ok1(len == strlen("{\"") + i + strlen("\":")
+ quote * 2 + strlen(escaped) * i + strlen("}"));
ok1(len > strlen("{\""));
ok1(memcmp(r, "{\"", strlen("{\"")) == 0);
json_out_consume(jout, strlen("{\""));
r = json_out_contents(jout, &len);
ok1(len > strlen(fieldname));
ok1(memcmp(r, fieldname, strlen(fieldname)) == 0);
json_out_consume(jout, strlen(fieldname));
r = json_out_contents(jout, &len);
ok1(len > strlen("\":"));
ok1(memcmp(r, "\":", strlen("\":")) == 0);
json_out_consume(jout, strlen("\":"));
r = json_out_contents(jout, &len);
if (quote) {
ok1(len > 0);
ok1(r[0] == '"');
json_out_consume(jout, 1);
}
for (size_t n = 0; n < i; n++) {
r = json_out_contents(jout, &len);
ok1(len > strlen(escaped));
ok1(memcmp(r, escaped, strlen(escaped)) == 0);
json_out_consume(jout, strlen(escaped));
}
r = json_out_contents(jout, &len);
if (quote) {
ok1(len > 0);
ok1(r[0] == '"');
json_out_consume(jout, 1);
}
r = json_out_contents(jout, &len);
ok1(len == 1);
ok1(memcmp(r, "}", 1) == 0);
json_out_consume(jout, 1);
ok1(!json_out_contents(jout, &len));
ok1(len == 0);
}
}
static void json_eq(const struct json_out *jout, const char *expect)
{
size_t len;
const char *p;
json_out_finished(jout);
p = json_out_contents(jout, &len);
ok1(len == strlen(expect));
ok1(memcmp(expect, p, len) == 0);
}
int main(void)
{
const tal_t *ctx = tal(NULL, char);
struct json_out *jout;
char *p;
/* This is how many tests you plan to run */
plan_tests(14689);
/* Simple tests */
test_json_out_add(ctx, '1', false, "1");
test_json_out_add(ctx, 'x', true, "x");
test_json_out_add(ctx, '\n', true, "\\n");
/* Test nested arrays. */
jout = json_out_new(ctx);
for (size_t i = 0; i < 64; i++)
json_out_start(jout, NULL, '[');
for (size_t i = 0; i < 64; i++)
json_out_end(jout, ']');
json_eq(jout, "[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]");
/* Test nested objects. */
jout = json_out_new(ctx);
json_out_start(jout, NULL, '{');
for (size_t i = 0; i < 63; i++)
json_out_start(jout, "x", '{');
for (size_t i = 0; i < 64; i++)
json_out_end(jout, '}');
json_eq(jout, "{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}");
jout = json_out_new(ctx);
json_out_start(jout, NULL, '{');
p = json_out_member_direct(jout, "x", 7);
memcpy(p, "\"hello\"", 7);
json_out_end(jout, '}');
json_eq(jout, "{\"x\":\"hello\"}");
jout = json_out_new(ctx);
p = json_out_direct(jout, strlen("{\"x\":\"hello\"}\n"));
memcpy(p, "{\"x\":\"hello\"}\n", strlen("{\"x\":\"hello\"}\n"));
json_eq(jout, "{\"x\":\"hello\"}\n");
jout = json_out_new(ctx);
json_out_start(jout, NULL, '{');
struct json_out *jout2 = json_out_new(ctx);
json_out_start(jout2, NULL, '{');
json_out_addstr(jout2, "x", "hello");
json_out_end(jout2, '}');
json_out_finished(jout2);
json_out_add_splice(jout, "inner", jout2);
json_out_end(jout, '}');
json_eq(jout, "{\"inner\":{\"x\":\"hello\"}}");
tal_free(ctx);
/* This exits depending on whether all tests passed */
return exit_status();
}

1
cli/Makefile

@ -4,7 +4,6 @@ LIGHTNING_CLI_OBJS := $(LIGHTNING_CLI_SRC:.c=.o)
LIGHTNING_CLI_COMMON_OBJS := \
common/configdir.o \
common/json.o \
common/json_escaped.o \
common/memleak.o \
common/utils.o \
common/version.o

2
cli/lightning-cli.c

@ -5,6 +5,7 @@
#include <assert.h>
#include <ccan/asort/asort.h>
#include <ccan/err/err.h>
#include <ccan/json_escape/json_escape.h>
#include <ccan/opt/opt.h>
#include <ccan/read_write_all/read_write_all.h>
#include <ccan/str/str.h>
@ -12,7 +13,6 @@
#include <common/configdir.h>
#include <common/json.h>
#include <common/json_command.h>
#include <common/json_escaped.h>
#include <common/memleak.h>
#include <common/utils.h>
#include <common/version.h>

1
cli/test/Makefile

@ -12,7 +12,6 @@ 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 \

1
common/Makefile

@ -28,7 +28,6 @@ COMMON_SRC_NOGEN := \
common/initial_commit_tx.c \
common/io_lock.c \
common/json.c \
common/json_escaped.c \
common/json_helpers.c \
common/json_tok.c \
common/key_derive.c \

35
common/json_escaped.h

@ -1,35 +0,0 @@
#ifndef LIGHTNING_COMMON_JSON_ESCAPED_H
#define LIGHTNING_COMMON_JSON_ESCAPED_H
#include "config.h"
#include <common/json.h>
/* Type differentiation for a correctly-escaped JSON string */
struct json_escaped {
/* NUL terminated string. */
char s[1];
};
/* @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_to_escaped_string(const tal_t *ctx,
const char *buffer,
const jsmntok_t *tok);
/* Are two escaped json strings identical? */
bool json_escaped_eq(const struct json_escaped *a,
const struct json_escaped *b);
/* Internal routine for creating json_escaped from bytes. */
struct json_escaped *json_escaped_string_(const tal_t *ctx,
const void *bytes, size_t len);
/* Be very careful here! Can fail! Doesn't handle \u: use UTF-8 please. */
const char *json_escaped_unescape(const tal_t *ctx,
const struct json_escaped *esc);
#endif /* LIGHTNING_COMMON_JSON_ESCAPED_H */

15
common/json_tok.c

@ -1,9 +1,9 @@
#include <ccan/crypto/sha256/sha256.h>
#include <ccan/json_escape/json_escape.h>
#include <ccan/str/hex/hex.h>
#include <ccan/tal/str/str.h>
#include <common/amount.h>
#include <common/json_command.h>
#include <common/json_escaped.h>
#include <common/json_tok.h>
#include <common/jsonrpc_errors.h>
#include <common/param.h>
@ -53,9 +53,12 @@ struct command_result *param_escaped_string(struct command *cmd,
const jsmntok_t *tok,
const char **str)
{
struct json_escaped *esc = json_to_escaped_string(cmd, buffer, tok);
if (esc) {
*str = json_escaped_unescape(cmd, esc);
if (tok->type == JSMN_STRING) {
struct json_escape *esc;
/* jsmn always gives us ~ well-formed strings. */
esc = json_escape_string_(cmd, buffer + tok->start,
tok->end - tok->start);
*str = json_escape_unescape(cmd, esc);
if (*str)
return NULL;
}
@ -77,10 +80,10 @@ struct command_result *param_string(struct command *cmd, const char *name,
struct command_result *param_label(struct command *cmd, const char *name,
const char * buffer, const jsmntok_t *tok,
struct json_escaped **label)
struct json_escape **label)
{
/* We accept both strings and number literals here. */
*label = json_escaped_string_(cmd, buffer + tok->start, tok->end - tok->start);
*label = json_escape_string_(cmd, buffer + tok->start, tok->end - tok->start);
if (*label && (tok->type == JSMN_STRING || json_tok_is_num(buffer, tok)))
return NULL;

4
common/json_tok.h

@ -9,7 +9,7 @@ struct amount_msat;
struct amount_sat;
struct command;
struct command_result;
struct json_escaped;
struct json_escape;
struct sha256;
/* Extract json array token */
@ -42,7 +42,7 @@ struct command_result *param_string(struct command *cmd, const char *name,
/* Extract a label. It is either an escaped string or a number. */
struct command_result *param_label(struct command *cmd, const char *name,
const char * buffer, const jsmntok_t *tok,
struct json_escaped **label);
struct json_escape **label);
/* Extract number from this (may be a string, or a number literal) */
struct command_result *param_number(struct command *cmd, const char *name,

46
common/test/run-json_escaped.c

@ -1,46 +0,0 @@
#include "../json_escaped.c"
#include <assert.h>
#include <common/utils.h>
#include <stdio.h>
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)
{
setup_locale();
test_json_partial();
assert(!taken_any());
take_cleanup();
}

7
common/test/run-param.c

@ -1,7 +1,6 @@
#include "config.h"
#include "../amount.c"
#include "../json.c"
#include "../json_escaped.c"
#include "../json_tok.c"
#include "../param.c"
#include <ccan/array_size/array_size.h>
@ -438,7 +437,7 @@ static void advanced(void)
{
struct json *j = json_parse(cmd, "[ 'lightning', 24, 'tok', 543 ]");
struct json_escaped *label;
struct json_escape *label;
u64 *msat;
u64 *msat_opt1, *msat_opt2;
const jsmntok_t *tok;
@ -460,7 +459,7 @@ static void advanced(void)
}
{
struct json *j = json_parse(cmd, "[ 3, 'foo' ]");
struct json_escaped *label, *foo;
struct json_escape *label, *foo;
assert(param(cmd, j->buffer, j->toks,
p_req("label", param_label, &label),
p_opt("foo", param_label, &foo),
@ -532,7 +531,7 @@ static void test_invoice(struct command *cmd,
const jsmntok_t *params)
{
u64 *msatoshi_val;
struct json_escaped *label_val;
struct json_escape *label_val;
const char *desc_val;
u64 *expiry;
const jsmntok_t *fallbacks;

1
lightningd/Makefile

@ -36,7 +36,6 @@ LIGHTNINGD_COMMON_OBJS := \
common/key_derive.o \
common/io_lock.o \
common/json.o \
common/json_escaped.o \
common/json_helpers.o \
common/json_tok.o \
common/memleak.o \

4
lightningd/gossip_control.c

@ -8,12 +8,12 @@
#include <ccan/crypto/siphash24/siphash24.h>
#include <ccan/err/err.h>
#include <ccan/fdpass/fdpass.h>
#include <ccan/json_escape/json_escape.h>
#include <ccan/take/take.h>
#include <ccan/tal/str/str.h>
#include <common/amount.h>
#include <common/features.h>
#include <common/json_command.h>
#include <common/json_escaped.h>
#include <common/json_helpers.h>
#include <common/jsonrpc_errors.h>
#include <common/param.h>
@ -202,7 +202,7 @@ static void json_getnodes_reply(struct subd *gossip UNUSED, const u8 *reply,
json_array_start(response, "nodes");
for (i = 0; i < tal_count(nodes); i++) {
struct json_escaped *esc;
struct json_escape *esc;
json_object_start(response, NULL);
json_add_node_id(response, "nodeid", &nodes[i]->nodeid);

16
lightningd/invoice.c

@ -6,13 +6,13 @@
#include <bitcoin/base58.h>
#include <bitcoin/script.h>
#include <ccan/array_size/array_size.h>
#include <ccan/json_escape/json_escape.h>
#include <ccan/str/hex/hex.h>
#include <ccan/tal/str/str.h>
#include <common/amount.h>
#include <common/bech32.h>
#include <common/bolt11.h>
#include <common/json_command.h>
#include <common/json_escaped.h>
#include <common/json_helpers.h>
#include <common/jsonrpc_errors.h>
#include <common/overflows.h>
@ -108,7 +108,7 @@ struct invoice_payment_hook_payload {
/* Set to NULL if it is deleted while waiting for plugin */
struct htlc_in *hin;
/* What invoice it's trying to pay. */
const struct json_escaped *label;
const struct json_escape *label;
/* Amount it's offering. */
struct amount_msat msat;
/* Preimage we'll give it if succeeds. */
@ -448,7 +448,7 @@ struct invoice_info {
struct command *cmd;
struct preimage payment_preimage;
struct bolt11 *b11;
struct json_escaped *label;
struct json_escape *label;
};
static void gossipd_incoming_channels_reply(struct subd *gossipd,
@ -799,7 +799,7 @@ AUTODATA(json_command, &invoice_command);
static void json_add_invoices(struct json_stream *response,
struct wallet *wallet,
const struct json_escaped *label)
const struct json_escape *label)
{
struct invoice_iterator it;
const struct invoice_details *details;
@ -826,7 +826,7 @@ static struct command_result *json_listinvoices(struct command *cmd,
const jsmntok_t *obj UNNEEDED,
const jsmntok_t *params)
{
struct json_escaped *label;
struct json_escape *label;
struct json_stream *response;
struct wallet *wallet = cmd->ld->wallet;
if (!param(cmd, buffer, params,
@ -859,7 +859,7 @@ static struct command_result *json_delinvoice(struct command *cmd,
const struct invoice_details *details;
struct json_stream *response;
const char *status, *actual_status;
struct json_escaped *label;
struct json_escape *label;
struct wallet *wallet = cmd->ld->wallet;
if (!param(cmd, buffer, params,
@ -978,7 +978,7 @@ static struct command_result *json_waitinvoice(struct command *cmd,
struct invoice i;
const struct invoice_details *details;
struct wallet *wallet = cmd->ld->wallet;
struct json_escaped *label;
struct json_escape *label;
if (!param(cmd, buffer, params,
p_req("label", param_label, &label),
@ -1079,7 +1079,7 @@ static struct command_result *json_decodepay(struct command *cmd,
json_add_amount_msat_compat(response, *b11->msat,
"msatoshi", "amount_msat");
if (b11->description) {
struct json_escaped *esc = json_escape(NULL, b11->description);
struct json_escape *esc = json_escape(NULL, b11->description);
json_add_escaped_string(response, "description", take(esc));
}
if (b11->description_hash)

6
lightningd/json.c

@ -1,10 +1,10 @@
#include <arpa/inet.h>
#include <ccan/json_escape/json_escape.h>
#include <ccan/mem/mem.h>
#include <ccan/str/hex/hex.h>
#include <ccan/tal/str/str.h>
#include <common/json.h>
#include <common/json_command.h>
#include <common/json_escaped.h>
#include <common/json_helpers.h>
#include <common/jsonrpc_errors.h>
#include <common/memleak.h>
@ -349,7 +349,7 @@ void json_add_literal(struct json_stream *result, const char *fieldname,
void json_add_string(struct json_stream *result, const char *fieldname, const char *value TAKES)
{
struct json_escaped *esc = json_partial_escape(NULL, value);
struct json_escape *esc = json_partial_escape(NULL, value);
json_add_member(result, fieldname, "\"%s\"", esc->s);
tal_free(esc);
@ -380,7 +380,7 @@ void json_add_tx(struct json_stream *result,
}
void json_add_escaped_string(struct json_stream *result, const char *fieldname,
const struct json_escaped *esc TAKES)
const struct json_escape *esc TAKES)
{
json_add_member(result, fieldname, "\"%s\"", esc->s);
if (taken(esc))

4
lightningd/json.h

@ -22,7 +22,7 @@ struct bitcoin_txid;
struct chainparams;
struct channel_id;
struct command;
struct json_escaped;
struct json_escape;
struct json_stream;
struct pubkey;
struct node_id;
@ -123,7 +123,7 @@ void json_add_string(struct json_stream *result, const char *fieldname, const ch
* already be JSON escaped as necessary. */
void json_add_escaped_string(struct json_stream *result,
const char *fieldname,
const struct json_escaped *esc TAKES);
const struct json_escape *esc TAKES);
/* '"fieldname" : literal' or 'literal' if fieldname is NULL*/
void json_add_literal(struct json_stream *result, const char *fieldname,

6
lightningd/jsonrpc.c

@ -22,12 +22,12 @@
#include <ccan/asort/asort.h>
#include <ccan/err/err.h>
#include <ccan/io/io.h>
#include <ccan/json_escape/json_escape.h>
#include <ccan/str/hex/hex.h>
#include <ccan/strmap/strmap.h>
#include <ccan/tal/str/str.h>
#include <common/bech32.h>
#include <common/json_command.h>
#include <common/json_escaped.h>
#include <common/jsonrpc_errors.h>
#include <common/memleak.h>
#include <common/param.h>
@ -332,7 +332,7 @@ static void json_add_help_command(struct command *cmd,
" a description for this"
" json_command!");
} else {
struct json_escaped *esc;
struct json_escape *esc;
esc = json_escape(NULL, json_command->verbose);
json_add_escaped_string(response, "verbose", take(esc));
@ -551,7 +551,7 @@ struct json_stream *json_stream_fail_nodata(struct command *cmd,
const char *errmsg)
{
struct json_stream *r = json_start(cmd);
struct json_escaped *e = json_partial_escape(tmpctx, errmsg);
struct json_escape *e = json_partial_escape(tmpctx, errmsg);
assert(code);

2
lightningd/lightningd.c

@ -46,6 +46,7 @@
#include <ccan/err/err.h>
#include <ccan/io/fdpass/fdpass.h>
#include <ccan/io/io.h>
#include <ccan/json_escape/json_escape.h>
#include <ccan/noerr/noerr.h>
#include <ccan/pipecmd/pipecmd.h>
#include <ccan/read_write_all/read_write_all.h>
@ -57,7 +58,6 @@
/*~ This is common code: routines shared by one or more executables
* (separate daemons, or the lightning-cli program). */
#include <common/daemon.h>
#include <common/json_escaped.h>
#include <common/timeout.h>
#include <common/utils.h>
#include <common/version.h>

4
lightningd/options.c

@ -1,6 +1,7 @@
#include <bitcoin/chainparams.h>
#include <ccan/array_size/array_size.h>
#include <ccan/err/err.h>
#include <ccan/json_escape/json_escape.h>
#include <ccan/mem/mem.h>
#include <ccan/opt/opt.h>
#include <ccan/opt/private.h>
@ -11,7 +12,6 @@
#include <ccan/tal/str/str.h>
#include <common/configdir.h>
#include <common/json_command.h>
#include <common/json_escaped.h>
#include <common/jsonrpc_errors.h>
#include <common/memleak.h>
#include <common/param.h>
@ -1044,7 +1044,7 @@ static void add_config(struct lightningd *ld,
}
if (answer) {
struct json_escaped *esc = json_escape(NULL, answer);
struct json_escape *esc = json_escape(NULL, answer);
json_add_escaped_string(response, name0, take(esc));
}
tal_free(name0);

1
lightningd/peer_htlcs.c

@ -7,7 +7,6 @@
#include <ccan/tal/str/str.h>
#include <channeld/gen_channel_wire.h>
#include <common/json_command.h>
#include <common/json_escaped.h>
#include <common/jsonrpc_errors.h>
#include <common/overflows.h>
#include <common/param.h>

1
lightningd/test/Makefile

@ -14,7 +14,6 @@ LIGHTNINGD_TEST_COMMON_OBJS := \
common/htlc_state.o \
common/io_lock.o \
common/json.o \
common/json_escaped.o \
common/key_derive.o \
common/pseudorand.o \
common/memleak.o \

8
lightningd/test/run-invoice-select-inchan.c

@ -154,7 +154,7 @@ void json_add_bool(struct json_stream *result UNNEEDED, const char *fieldname UN
/* Generated stub for json_add_escaped_string */
void json_add_escaped_string(struct json_stream *result UNNEEDED,
const char *fieldname UNNEEDED,
const struct json_escaped *esc TAKES UNNEEDED)
const struct json_escape *esc TAKES UNNEEDED)
{ fprintf(stderr, "json_add_escaped_string called!\n"); abort(); }
/* Generated stub for json_add_hex */
void json_add_hex(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED,
@ -323,7 +323,7 @@ struct command_result *param_escaped_string(struct command *cmd UNNEEDED,
/* Generated stub for param_label */
struct command_result *param_label(struct command *cmd UNNEEDED, const char *name UNNEEDED,
const char * buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
struct json_escaped **label UNNEEDED)
struct json_escape **label UNNEEDED)
{ fprintf(stderr, "param_label called!\n"); abort(); }
/* Generated stub for param_loglevel */
struct command_result *param_loglevel(struct command *cmd UNNEEDED,
@ -495,7 +495,7 @@ bool wallet_htlcs_load_for_channel(struct wallet *wallet UNNEEDED,
bool wallet_invoice_create(struct wallet *wallet UNNEEDED,
struct invoice *pinvoice UNNEEDED,
const struct amount_msat *msat TAKES UNNEEDED,
const struct json_escaped *label TAKES UNNEEDED,
const struct json_escape *label TAKES UNNEEDED,
u64 expiry UNNEEDED,
const char *b11enc UNNEEDED,
const char *description UNNEEDED,
@ -518,7 +518,7 @@ const struct invoice_details *wallet_invoice_details(const tal_t *ctx UNNEEDED,
/* Generated stub for wallet_invoice_find_by_label */
bool wallet_invoice_find_by_label(struct wallet *wallet UNNEEDED,
struct invoice *pinvoice UNNEEDED,
const struct json_escaped *label UNNEEDED)
const struct json_escape *label UNNEEDED)
{ fprintf(stderr, "wallet_invoice_find_by_label called!\n"); abort(); }
/* Generated stub for wallet_invoice_find_by_rhash */
bool wallet_invoice_find_by_rhash(struct wallet *wallet UNNEEDED,

2
lightningd/test/run-jsonrpc.c

@ -141,7 +141,7 @@ static void test_json_escape(void)
for (i = 1; i < 256; i++) {
char badstr[2];
struct json_stream *result = new_json_stream(NULL, NULL, NULL);
struct json_escaped *esc;
struct json_escape *esc;
badstr[0] = i;
badstr[1] = 0;

1
plugins/Makefile

@ -25,7 +25,6 @@ PLUGIN_COMMON_OBJS := \
common/daemon.o \
common/hash_u5.o \
common/json.o \
common/json_escaped.o \
common/json_helpers.o \
common/json_tok.o \
common/memleak.o \

16
wallet/db.c

@ -1,8 +1,8 @@
#include "db.h"
#include <ccan/array_size/array_size.h>
#include <ccan/json_escape/json_escape.h>
#include <ccan/tal/str/str.h>
#include <common/json_escaped.h>
#include <common/node_id.h>
#include <common/version.h>
#include <inttypes.h>
@ -1121,16 +1121,16 @@ bool sqlite3_bind_sha256_double(sqlite3_stmt *stmt, int col, const struct sha256
return err == SQLITE_OK;
}
struct json_escaped *sqlite3_column_json_escaped(const tal_t *ctx,
sqlite3_stmt *stmt, int col)
struct json_escape *sqlite3_column_json_escape(const tal_t *ctx,
sqlite3_stmt *stmt, int col)
{
return json_escaped_string_(ctx,
sqlite3_column_blob(stmt, col),
sqlite3_column_bytes(stmt, col));
return json_escape_string_(ctx,
sqlite3_column_blob(stmt, col),
sqlite3_column_bytes(stmt, col));
}
bool sqlite3_bind_json_escaped(sqlite3_stmt *stmt, int col,
const struct json_escaped *esc)
bool sqlite3_bind_json_escape(sqlite3_stmt *stmt, int col,
const struct json_escape *esc)
{
int err = sqlite3_bind_text(stmt, col, esc->s, strlen(esc->s), SQLITE_TRANSIENT);
return err == SQLITE_OK;

8
wallet/db.h

@ -202,10 +202,10 @@ bool sqlite3_bind_sha256_double(sqlite3_stmt *stmt, int col, const struct sha256
struct secret *sqlite3_column_secrets(const tal_t *ctx,
sqlite3_stmt *stmt, int col);
struct json_escaped *sqlite3_column_json_escaped(const tal_t *ctx,
sqlite3_stmt *stmt, int col);
bool sqlite3_bind_json_escaped(sqlite3_stmt *stmt, int col,
const struct json_escaped *esc);
struct json_escape *sqlite3_column_json_escape(const tal_t *ctx,
sqlite3_stmt *stmt, int col);
bool sqlite3_bind_json_escape(sqlite3_stmt *stmt, int col,
const struct json_escape *esc);
struct amount_msat sqlite3_column_amount_msat(sqlite3_stmt *stmt, int col);
struct amount_sat sqlite3_column_amount_sat(sqlite3_stmt *stmt, int col);

10
wallet/invoices.c

@ -96,7 +96,7 @@ static struct invoice_details *wallet_stmt2invoice_details(const tal_t *ctx,
sqlite3_column_sha256(stmt, 2, &dtl->rhash);
dtl->label = sqlite3_column_json_escaped(dtl, stmt, 3);
dtl->label = sqlite3_column_json_escape(dtl, stmt, 3);
if (sqlite3_column_type(stmt, 4) != SQLITE_NULL) {
dtl->msat = tal(dtl, struct amount_msat);
@ -255,7 +255,7 @@ static void install_expiration_timer(struct invoices *invoices)
bool invoices_create(struct invoices *invoices,
struct invoice *pinvoice,
const struct amount_msat *msat TAKES,
const struct json_escaped *label TAKES,
const struct json_escape *label TAKES,
u64 expiry,
const char *b11enc,
const char *description,
@ -300,7 +300,7 @@ bool invoices_create(struct invoices *invoices,
sqlite3_bind_amount_msat(stmt, 4, *msat);
else
sqlite3_bind_null(stmt, 4);
sqlite3_bind_json_escaped(stmt, 5, label);
sqlite3_bind_json_escape(stmt, 5, label);
sqlite3_bind_int64(stmt, 6, expiry_time);
sqlite3_bind_text(stmt, 7, b11enc, strlen(b11enc), SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 8, description, strlen(description), SQLITE_TRANSIENT);
@ -327,7 +327,7 @@ bool invoices_create(struct invoices *invoices,
bool invoices_find_by_label(struct invoices *invoices,
struct invoice *pinvoice,
const struct json_escaped *label)
const struct json_escape *label)
{
sqlite3_stmt *stmt;
@ -335,7 +335,7 @@ bool invoices_find_by_label(struct invoices *invoices,
"id"
" FROM invoices"
" WHERE label = ?;");
sqlite3_bind_json_escaped(stmt, 1, label);
sqlite3_bind_json_escape(stmt, 1, label);
if (!db_select_step(invoices->db, stmt))
return false;

6
wallet/invoices.h

@ -8,7 +8,7 @@
struct amount_msat;
struct db;
struct json_escaped;
struct json_escape;
struct invoice;
struct invoice_details;
struct invoice_iterator;
@ -49,7 +49,7 @@ struct invoices *invoices_new(const tal_t *ctx,
bool invoices_create(struct invoices *invoices,
struct invoice *pinvoice,
const struct amount_msat *msat TAKES,
const struct json_escaped *label TAKES,
const struct json_escape *label TAKES,
u64 expiry,
const char *b11enc,
const char *description,
@ -68,7 +68,7 @@ bool invoices_create(struct invoices *invoices,
*/
bool invoices_find_by_label(struct invoices *invoices,
struct invoice *pinvoice,
const struct json_escaped *label);
const struct json_escape *label);
/**
* invoices_find_by_rhash - Search for an invoice by

4
wallet/test/run-db.c

@ -18,10 +18,6 @@ static void db_log_(struct log *log UNUSED, enum log_level level UNUSED, bool ca
#include <unistd.h>
/* AUTOGENERATED MOCKS START */
/* Generated stub for json_escaped_string_ */
struct json_escaped *json_escaped_string_(const tal_t *ctx UNNEEDED,
const void *bytes UNNEEDED, size_t len UNNEEDED)
{ fprintf(stderr, "json_escaped_string_ called!\n"); abort(); }
/* AUTOGENERATED MOCKS END */
static char *db_err;

8
wallet/test/run-wallet.c

@ -123,7 +123,7 @@ bool htlc_is_trimmed(enum side htlc_owner UNNEEDED,
bool invoices_create(struct invoices *invoices UNNEEDED,
struct invoice *pinvoice UNNEEDED,
const struct amount_msat *msat TAKES UNNEEDED,
const struct json_escaped *label TAKES UNNEEDED,
const struct json_escape *label TAKES UNNEEDED,
u64 expiry UNNEEDED,
const char *b11enc UNNEEDED,
const char *description UNNEEDED,
@ -141,7 +141,7 @@ void invoices_delete_expired(struct invoices *invoices UNNEEDED,
/* Generated stub for invoices_find_by_label */
bool invoices_find_by_label(struct invoices *invoices UNNEEDED,
struct invoice *pinvoice UNNEEDED,
const struct json_escaped *label UNNEEDED)
const struct json_escape *label UNNEEDED)
{ fprintf(stderr, "invoices_find_by_label called!\n"); abort(); }
/* Generated stub for invoices_find_by_rhash */
bool invoices_find_by_rhash(struct invoices *invoices UNNEEDED,
@ -305,10 +305,6 @@ void json_array_end(struct json_stream *js UNNEEDED)
/* Generated stub for json_array_start */
void json_array_start(struct json_stream *js UNNEEDED, const char *fieldname UNNEEDED)
{ fprintf(stderr, "json_array_start called!\n"); abort(); }
/* Generated stub for json_escaped_string_ */
struct json_escaped *json_escaped_string_(const tal_t *ctx UNNEEDED,
const void *bytes UNNEEDED, size_t len UNNEEDED)
{ fprintf(stderr, "json_escaped_string_ called!\n"); abort(); }
/* Generated stub for json_get_member */
const jsmntok_t *json_get_member(const char *buffer UNNEEDED, const jsmntok_t tok[] UNNEEDED,
const char *label UNNEEDED)

4
wallet/wallet.c

@ -1629,7 +1629,7 @@ bool wallet_htlcs_load_for_channel(struct wallet *wallet,
bool wallet_invoice_create(struct wallet *wallet,
struct invoice *pinvoice,
const struct amount_msat *msat TAKES,
const struct json_escaped *label TAKES,
const struct json_escape *label TAKES,
u64 expiry,
const char *b11enc,
const char *description,
@ -1640,7 +1640,7 @@ bool wallet_invoice_create(struct wallet *wallet,
}
bool wallet_invoice_find_by_label(struct wallet *wallet,
struct invoice *pinvoice,
const struct json_escaped *label)
const struct json_escape *label)
{
return invoices_find_by_label(wallet->invoices, pinvoice, label);
}

6
wallet/wallet.h

@ -641,7 +641,7 @@ struct invoice_details {
/* Hash of preimage r */
struct sha256 rhash;
/* Label assigned by user */
const struct json_escaped *label;
const struct json_escape *label;
/* NULL if they specified "any" */
struct amount_msat *msat;
/* Absolute UNIX epoch time this will expire */
@ -693,7 +693,7 @@ struct invoice {
bool wallet_invoice_create(struct wallet *wallet,
struct invoice *pinvoice,
const struct amount_msat *msat TAKES,
const struct json_escaped *label TAKES,
const struct json_escape *label TAKES,
u64 expiry,
const char *b11enc,
const char *description,
@ -712,7 +712,7 @@ bool wallet_invoice_create(struct wallet *wallet,
*/
bool wallet_invoice_find_by_label(struct wallet *wallet,
struct invoice *pinvoice,
const struct json_escaped *label);
const struct json_escape *label);
/**
* wallet_invoice_find_by_rhash - Search for an invoice by payment_hash

Loading…
Cancel
Save