mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-03 20:44:54 +01:00
c3f433ec66
It turns out we were heavily relying on the fact that after each message from the client there'd be a flush, and that there would not be anything after the JSON object we read. This will no longer be the case once we start streaming things or we are very quick in issuing the JSON-RPC requests. This just takes one of the error paths (incomplete read) and makes it into a successful path if we have indeed read a full root element.
191 lines
5.3 KiB
C
191 lines
5.3 KiB
C
#include "../json.c"
|
|
#include "../json_escaped.c"
|
|
#include <common/utils.h>
|
|
#include <stdio.h>
|
|
|
|
/* AUTOGENERATED MOCKS START */
|
|
/* AUTOGENERATED MOCKS END */
|
|
|
|
|
|
// issue #577
|
|
|
|
static void do_json_tok_bitcoin_amount(const char* val, uint64_t expected)
|
|
{
|
|
uint64_t amount;
|
|
jsmntok_t tok;
|
|
|
|
tok.start = 0;
|
|
tok.end = strlen(val);
|
|
|
|
fprintf(stderr, "do_json_tok_bitcoin_amount(\"%s\", %"PRIu64"): ", val, expected);
|
|
|
|
assert(json_tok_bitcoin_amount(val, &tok, &amount) == true);
|
|
assert(amount == expected);
|
|
|
|
fprintf(stderr, "ok\n");
|
|
}
|
|
|
|
|
|
static int test_json_tok_bitcoin_amount(void)
|
|
{
|
|
do_json_tok_bitcoin_amount("0.00000001", 1);
|
|
do_json_tok_bitcoin_amount("0.00000007", 7);
|
|
do_json_tok_bitcoin_amount("0.00000008", 8);
|
|
do_json_tok_bitcoin_amount("0.00000010", 10);
|
|
do_json_tok_bitcoin_amount("0.12345678", 12345678);
|
|
do_json_tok_bitcoin_amount("0.01234567", 1234567);
|
|
do_json_tok_bitcoin_amount("123.45678900", 12345678900);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int test_json_filter(void)
|
|
{
|
|
struct json_result *result = new_json_result(NULL);
|
|
jsmntok_t *toks;
|
|
const jsmntok_t *x;
|
|
bool valid;
|
|
int i;
|
|
char *badstr = tal_arr(result, char, 256);
|
|
const char *str;
|
|
|
|
/* Fill with junk, and nul-terminate (256 -> 0) */
|
|
for (i = 1; i < 257; i++)
|
|
badstr[i-1] = i;
|
|
|
|
json_object_start(result, NULL);
|
|
json_add_string(result, "x", badstr);
|
|
json_object_end(result);
|
|
|
|
/* Parse back in, make sure nothing crazy. */
|
|
str = json_result_string(result);
|
|
|
|
toks = json_parse_input(str, strlen(str), &valid);
|
|
assert(valid);
|
|
assert(toks);
|
|
|
|
assert(toks[0].type == JSMN_OBJECT);
|
|
x = json_get_member(str, toks, "x");
|
|
assert(x);
|
|
assert(x->type == JSMN_STRING);
|
|
|
|
/* 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((unsigned)str[i] >= ' ');
|
|
assert((unsigned)str[i] != 127);
|
|
}
|
|
tal_free(result);
|
|
return 0;
|
|
}
|
|
|
|
static void test_json_escape(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 1; i < 256; i++) {
|
|
char badstr[2];
|
|
struct json_result *result = new_json_result(NULL);
|
|
struct json_escaped *esc;
|
|
|
|
badstr[0] = i;
|
|
badstr[1] = 0;
|
|
|
|
json_object_start(result, NULL);
|
|
esc = json_escape(NULL, badstr);
|
|
json_add_escaped_string(result, "x", take(esc));
|
|
json_object_end(result);
|
|
|
|
const char *str = json_result_string(result);
|
|
if (i == '\\' || i == '"'
|
|
|| i == '\n' || i == '\r' || i == '\b'
|
|
|| i == '\t' || i == '\f')
|
|
assert(strstarts(str, "\n{\n \"x\": \"\\"));
|
|
else if (i < 32 || i == 127) {
|
|
assert(strstarts(str, "\n{\n \"x\": \"\\u00"));
|
|
} else {
|
|
char expect[] = "\n{\n \"x\": \"?\"\n}";
|
|
expect[11] = i;
|
|
assert(streq(str, expect));
|
|
}
|
|
tal_free(result);
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
/* Test that we can segment and parse a stream of json objects correctly. */
|
|
static void test_json_stream(void)
|
|
{
|
|
bool valid;
|
|
char *input, *talstr;
|
|
jsmntok_t *toks;
|
|
|
|
/* Multiple full messages in a single buffer (happens when buffer
|
|
* boundary coincides with message boundary, or read returned after
|
|
* timeout. */
|
|
input = "{\"x\":\"x\"}{\"y\":\"y\"}";
|
|
talstr = tal_strndup(NULL, input, strlen(input));
|
|
toks = json_parse_input(talstr, strlen(talstr), &valid);
|
|
assert(toks);
|
|
assert(tal_count(toks) == 4);
|
|
assert(toks[0].start == 0 && toks[0].end == 9);
|
|
assert(valid);
|
|
tal_free(talstr);
|
|
|
|
/* Multiple messages, and the last one is partial, far more likely than
|
|
* accidentally getting the boundaries to match. */
|
|
input = "{\"x\":\"x\"}{\"y\":\"y\"}{\"z\":\"z";
|
|
talstr = tal_strndup(NULL, input, strlen(input));
|
|
toks = json_parse_input(talstr, strlen(talstr), &valid);
|
|
assert(toks);
|
|
assert(tal_count(toks) == 4);
|
|
assert(toks[0].start == 0 && toks[0].end == 9);
|
|
assert(valid);
|
|
tal_free(talstr);
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
setup_locale();
|
|
|
|
test_json_tok_bitcoin_amount();
|
|
test_json_filter();
|
|
test_json_escape();
|
|
test_json_partial();
|
|
test_json_stream();
|
|
assert(!taken_any());
|
|
take_cleanup();
|
|
}
|