mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-18 05:12:45 +01:00
json: Support streaming JSON messages
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.
This commit is contained in:
parent
fc12f65a3d
commit
c3f433ec66
@ -188,23 +188,34 @@ jsmntok_t *json_parse_input(const char *input, int len, bool *valid)
|
||||
int ret;
|
||||
|
||||
toks = tal_arr(input, jsmntok_t, 10);
|
||||
toks[0].type = JSMN_UNDEFINED;
|
||||
|
||||
again:
|
||||
jsmn_init(&parser);
|
||||
again:
|
||||
ret = jsmn_parse(&parser, input, len, toks, tal_count(toks) - 1);
|
||||
|
||||
switch (ret) {
|
||||
case JSMN_ERROR_INVAL:
|
||||
*valid = false;
|
||||
return tal_free(toks);
|
||||
case JSMN_ERROR_PART:
|
||||
*valid = true;
|
||||
return tal_free(toks);
|
||||
case JSMN_ERROR_NOMEM:
|
||||
tal_resize(&toks, tal_count(toks) * 2);
|
||||
goto again;
|
||||
}
|
||||
|
||||
/* Check whether we read at least one full root element, i.e., root
|
||||
* element has its end set. */
|
||||
if (toks[0].type == JSMN_UNDEFINED || toks[0].end == -1) {
|
||||
*valid = true;
|
||||
return tal_free(toks);
|
||||
}
|
||||
|
||||
/* If we read a partial element at the end of the stream we'll get a
|
||||
* ret=JSMN_ERROR_PART, but due to the previous check we know we read at
|
||||
* least one full element, so count tokens that are part of this root
|
||||
* element. */
|
||||
ret = json_next(toks) - toks;
|
||||
|
||||
/* Cut to length and return. */
|
||||
*valid = true;
|
||||
tal_resize(&toks, ret + 1);
|
||||
|
@ -145,6 +145,37 @@ static void test_json_partial(void)
|
||||
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();
|
||||
@ -153,6 +184,7 @@ int main(void)
|
||||
test_json_filter();
|
||||
test_json_escape();
|
||||
test_json_partial();
|
||||
test_json_stream();
|
||||
assert(!taken_any());
|
||||
take_cleanup();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user