From: Stephan Bosch Date: Wed, 7 Aug 2019 22:36:17 +0000 (+0200) Subject: lib-json: json-ostream - Add support for writing a JSON string from an input stream X-Git-Tag: 2.4.0~2386 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=59acecab3c49cd8843741b87ce06e6b2eb736710;p=thirdparty%2Fdovecot%2Fcore.git lib-json: json-ostream - Add support for writing a JSON string from an input stream --- diff --git a/src/lib-json/json-ostream.c b/src/lib-json/json-ostream.c index 89c8193e17..587185b3eb 100644 --- a/src/lib-json/json-ostream.c +++ b/src/lib-json/json-ostream.c @@ -3,6 +3,7 @@ #include "lib.h" #include "str.h" #include "array.h" +#include "istream.h" #include "ostream.h" #include "json-ostream.h" @@ -635,6 +636,33 @@ void json_ostream_nwritef_string(struct json_ostream *stream, va_end(args); } +int json_ostream_write_string_stream(struct json_ostream *stream, + const char *name, struct istream *input) +{ + struct json_value jvalue; + + i_zero(&jvalue); + jvalue.content_type = JSON_CONTENT_TYPE_STREAM; + jvalue.content.stream = input; + + return json_ostream_write_value(stream, name, JSON_TYPE_STRING, + &jvalue); +} + +void json_ostream_nwrite_string_stream(struct json_ostream *stream, + const char *name, struct istream *input) +{ + struct json_value jvalue; + + i_zero(&jvalue); + jvalue.content_type = JSON_CONTENT_TYPE_STREAM; + jvalue.content.stream = input; + + json_ostream_nwrite_value(stream, name, JSON_TYPE_STRING, &jvalue); + if (input->stream_errno != 0) + stream->nfailed = TRUE; +} + int json_ostream_open_string(struct json_ostream *stream, const char *name) { int ret; diff --git a/src/lib-json/json-ostream.h b/src/lib-json/json-ostream.h index de917af508..f2867fe406 100644 --- a/src/lib-json/json-ostream.h +++ b/src/lib-json/json-ostream.h @@ -169,6 +169,12 @@ void json_ostream_nwrite_string(struct json_ostream *stream, void json_ostream_nwritef_string(struct json_ostream *stream, const char *name, const char *format, ...) ATTR_FORMAT(3, 4); +/* Try to write the stream to the output stream as a string. Returns 1 + if buffered, 0 if not, -1 if error. */ +int json_ostream_write_string_stream(struct json_ostream *stream, + const char *name, struct istream *input); +void json_ostream_nwrite_string_stream(struct json_ostream *stream, + const char *name, struct istream *input); /* Open a string on the stream, which means that all subsequent string write functions are concatenated into a single JSON string value. Note that diff --git a/src/lib-json/test-json-ostream.c b/src/lib-json/test-json-ostream.c index 0fed58408a..8df070396a 100644 --- a/src/lib-json/test-json-ostream.c +++ b/src/lib-json/test-json-ostream.c @@ -2,6 +2,7 @@ #include "lib.h" #include "str.h" +#include "istream.h" #include "ostream.h" #include "test-common.h" @@ -14,8 +15,10 @@ static bool debug = FALSE; static void test_json_ostream_write(void) { string_t *buffer; + struct istream *input; struct ostream *output; struct json_ostream *joutput; + const char *data; unsigned int state, pos; int ret; @@ -88,6 +91,24 @@ static void test_json_ostream_write(void) str_truncate(buffer, 0); output->offset = 0; + /* string stream */ + test_begin("json ostream write - string stream"); + joutput = json_ostream_create(output, 0); + data = "AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ"; + input = i_stream_create_from_data(data, strlen(data)); + ret = json_ostream_write_string_stream(joutput, NULL, input); + i_assert(ret > 0); + i_stream_unref(&input); + ret = json_ostream_flush(joutput); + i_assert(ret > 0); + json_ostream_unref(&joutput); + test_assert_strcmp( + "\"AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ\"", + str_c(buffer)); + test_end(); + str_truncate(buffer, 0); + output->offset = 0; + /* */ test_begin("json ostream write - "); joutput = json_ostream_create(output, 0); @@ -133,6 +154,28 @@ static void test_json_ostream_write(void) str_truncate(buffer, 0); output->offset = 0; + /* [ string string stream ] */ + test_begin("json ostream write - array [ string stream ]"); + joutput = json_ostream_create(output, 0); + ret = json_ostream_descend_array(joutput, NULL); + i_assert(ret > 0); + data = "AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ"; + input = i_stream_create_from_data(data, strlen(data)); + ret = json_ostream_write_string_stream(joutput, NULL, input); + i_assert(ret > 0); + i_stream_unref(&input); + ret = json_ostream_ascend_array(joutput); + i_assert(ret > 0); + ret = json_ostream_flush(joutput); + i_assert(ret > 0); + json_ostream_unref(&joutput); + test_assert_strcmp( + "[\"AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ\"]", + str_c(buffer)); + test_end(); + str_truncate(buffer, 0); + output->offset = 0; + /* [ ] */ test_begin("json ostream write - array [ ]"); joutput = json_ostream_create(output, 0); @@ -201,6 +244,29 @@ static void test_json_ostream_write(void) str_truncate(buffer, 0); output->offset = 0; + /* { "frop": string stream } */ + test_begin("json ostream write - object { \"frop\": string stream }"); + joutput = json_ostream_create(output, 0); + ret = json_ostream_descend_object(joutput, NULL); + i_assert(ret > 0); + data = "AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ"; + input = i_stream_create_from_data(data, strlen(data)); + ret = json_ostream_write_string_stream(joutput, "frop", input); + i_assert(ret > 0); + i_stream_unref(&input); + ret = json_ostream_ascend_object(joutput); + i_assert(ret > 0); + ret = json_ostream_flush(joutput); + i_assert(ret > 0); + json_ostream_unref(&joutput); + test_assert_strcmp( + "{\"frop\":" + "\"AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ\"}", + str_c(buffer)); + test_end(); + str_truncate(buffer, 0); + output->offset = 0; + /* { "a": [{"d": 1}], "b": [{"e": 2}], "c": [{"f": 3}] } */ test_begin("json ostream write - " "object { \"a\": [{\"d\": 1}], \"b\": [{\"e\": 2}], " @@ -694,6 +760,156 @@ static void test_json_ostream_write(void) str_truncate(buffer, 0); output->offset = 0; + /* trickle[4] */ + test_begin("json ostream write - object, trickle[4]"); + o_stream_set_max_buffer_size(output, 0); + joutput = json_ostream_create(output, 0); + state = 0; + for (pos = 0; pos < 400 && state <= 16; pos++) { + o_stream_set_max_buffer_size(output, pos); + switch (state) { + case 0: + ret = json_ostream_descend_object(joutput, NULL); + i_assert(ret >= 0); + if (ret == 0) + break; + state++; + continue; + case 1: + ret = json_ostream_descend_array(joutput, "aaaaaa"); + i_assert(ret >= 0); + if (ret == 0) + break; + state++; + continue; + case 2: + ret = json_ostream_descend_object(joutput, NULL); + i_assert(ret >= 0); + if (ret == 0) + break; + data = "AAAAA"; + input = i_stream_create_from_data(data, strlen(data)); + state++; + continue; + case 3: + ret = json_ostream_write_string_stream( + joutput, "dddddd", input); + i_assert(ret >= 0); + if (ret == 0) + break; + i_stream_unref(&input); + state++; + continue; + case 4: + ret = json_ostream_ascend_object(joutput); + i_assert(ret >= 0); + if (ret == 0) + break; + state++; + continue; + case 5: + ret = json_ostream_ascend_array(joutput); + i_assert(ret >= 0); + if (ret == 0) + break; + state++; + continue; + case 6: + ret = json_ostream_descend_array(joutput, "bbbbbb"); + i_assert(ret >= 0); + if (ret == 0) + break; + state++; + continue; + case 7: + ret = json_ostream_descend_object(joutput, NULL); + i_assert(ret >= 0); + if (ret == 0) + break; + data = "BBBBB"; + input = i_stream_create_from_data(data, strlen(data)); + state++; + continue; + case 8: + ret = json_ostream_write_string_stream( + joutput, "eeeeee", input); + i_assert(ret >= 0); + if (ret == 0) + break; + i_stream_unref(&input); + state++; + continue; + case 9: + ret = json_ostream_ascend_object(joutput); + i_assert(ret >= 0); + if (ret == 0) + break; + state++; + continue; + case 10: + ret = json_ostream_ascend_array(joutput); + i_assert(ret >= 0); + if (ret == 0) + break; + state++; + continue; + case 11: + ret = json_ostream_descend_array(joutput, "cccccc"); + i_assert(ret >= 0); + if (ret == 0) + break; + state++; + continue; + case 12: + ret = json_ostream_descend_object(joutput, NULL); + i_assert(ret >= 0); + if (ret == 0) + break; + data = "CCCCC"; + input = i_stream_create_from_data(data, strlen(data)); + state++; + continue; + case 13: + ret = json_ostream_write_string_stream( + joutput, "ffffff", input); + i_assert(ret >= 0); + if (ret == 0) + break; + i_stream_unref(&input); + state++; + continue; + case 14: + ret = json_ostream_ascend_object(joutput); + i_assert(ret >= 0); + if (ret == 0) + break; + state++; + continue; + case 15: + ret = json_ostream_ascend_array(joutput); + i_assert(ret >= 0); + if (ret == 0) + break; + state++; + continue; + case 16: + ret = json_ostream_ascend_object(joutput); + i_assert(ret >= 0); + if (ret == 0) + break; + state++; + continue; + } + } + json_ostream_unref(&joutput); + test_assert_strcmp("{\"aaaaaa\":[{\"dddddd\":\"AAAAA\"}]," + "\"bbbbbb\":[{\"eeeeee\":\"BBBBB\"}]," + "\"cccccc\":[{\"ffffff\":\"CCCCC\"}]}", + str_c(buffer)); + test_end(); + str_truncate(buffer, 0); + output->offset = 0; + o_stream_destroy(&output); str_free(&buffer); } @@ -701,8 +917,10 @@ static void test_json_ostream_write(void) static void test_json_ostream_nwrite(void) { string_t *buffer; + struct istream *input; struct ostream *output; struct json_ostream *joutput; + const char *data; buffer = str_new(default_pool, 256); output = o_stream_create_buffer(buffer); @@ -768,6 +986,21 @@ static void test_json_ostream_nwrite(void) str_truncate(buffer, 0); output->offset = 0; + /* string stream */ + test_begin("json ostream nwrite - string stream"); + joutput = json_ostream_create(output, 0); + data = "AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ"; + input = i_stream_create_from_data(data, strlen(data)); + json_ostream_nwrite_string_stream(joutput, NULL, input); + i_stream_unref(&input); + json_ostream_nfinish_destroy(&joutput); + test_assert_strcmp( + "\"AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ\"", + str_c(buffer)); + test_end(); + str_truncate(buffer, 0); + output->offset = 0; + /* */ test_begin("json ostream nwrite - "); joutput = json_ostream_create(output, 0); @@ -801,6 +1034,23 @@ static void test_json_ostream_nwrite(void) str_truncate(buffer, 0); output->offset = 0; + /* [ string string stream ] */ + test_begin("json ostream nwrite - array [ string stream ]"); + joutput = json_ostream_create(output, 0); + json_ostream_ndescend_array(joutput, NULL); + data = "AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ"; + input = i_stream_create_from_data(data, strlen(data)); + json_ostream_nwrite_string_stream(joutput, NULL, input); + i_stream_unref(&input); + json_ostream_nascend_array(joutput); + json_ostream_nfinish_destroy(&joutput); + test_assert_strcmp( + "[\"AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ\"]", + str_c(buffer)); + test_end(); + str_truncate(buffer, 0); + output->offset = 0; + /* [ ] */ test_begin("json ostream nwrite - array [ ]"); joutput = json_ostream_create(output, 0); @@ -871,6 +1121,24 @@ static void test_json_ostream_nwrite(void) str_truncate(buffer, 0); output->offset = 0; + /* { "frop": string stream } */ + test_begin("json ostream nwrite - object { \"frop\": string stream }"); + joutput = json_ostream_create(output, 0); + json_ostream_ndescend_object(joutput, NULL); + data = "AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ"; + input = i_stream_create_from_data(data, strlen(data)); + json_ostream_nwrite_string_stream(joutput, "frop", input); + i_stream_unref(&input); + json_ostream_nascend_object(joutput); + json_ostream_nfinish_destroy(&joutput); + test_assert_strcmp( + "{\"frop\":" + "\"AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ\"}", + str_c(buffer)); + test_end(); + str_truncate(buffer, 0); + output->offset = 0; + /* concatenated string */ test_begin("json ostream nwrite - concatenated string"); joutput = json_ostream_create(output, 0);