From: Vladislav Shpilevoy <v.shpilevoy@tarantool.org> To: tarantool-patches@freelists.org Cc: vdavydov.dev@gmail.com Subject: [PATCH v2 03/10] yaml: introduce yaml.decode_tag Date: Fri, 20 Apr 2018 16:24:28 +0300 [thread overview] Message-ID: <0bce785538bba5d81f6c813732a7e309a941e175.1524228894.git.v.shpilevoy@tarantool.org> (raw) In-Reply-To: <cover.1524228894.git.v.shpilevoy@tarantool.org> In-Reply-To: <cover.1524228894.git.v.shpilevoy@tarantool.org> Yaml.decode_tag allows to decode a single tag of a YAML document. For #2677 it is needed to detect different push types in text console: print pushes via console.print, and actual pushes via box.session.push. To distinguish them YAML tags will be used. A client console for each message will try to find a tag. If a tag is absent, then the message is a simple response on a request. If a tag is !print!, then the document consists of a single string, that must be printed. Such a document must be decoded to get the printed string. So the calls sequence is yaml.decode_tag + yaml.decode. The reason why a print message must be decoded is that a print() result on a server side can be not well-formatted YAML, and must be encoded into it to be correctly send. For example, when I do on a server side something like this: console.print('very bad YAML string') The result of a print() is not a YAML document, and to be sent it must be encoded into YAML on a server side. If a tag is !push!, then the document is sent via box.session.push, and must not be decoded. It can be just printed or ignored or something. Needed for #2677 --- test/app-tap/yaml.test.lua | 30 ++++++++++++++++++- third_party/lua-yaml/lyaml.cc | 67 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) diff --git a/test/app-tap/yaml.test.lua b/test/app-tap/yaml.test.lua index b81402cc0..ef64509fe 100755 --- a/test/app-tap/yaml.test.lua +++ b/test/app-tap/yaml.test.lua @@ -70,7 +70,10 @@ local function test_output(test, s) end local function test_tagged(test, s) - test:plan(7) + test:plan(15) + -- + -- Test encoding tags. + -- local must_be_err = 'Usage: encode_tagged({prefix = <string>, handle = <string>}, object)' local prefix = 'tag:tarantool.io/push,2018' local ok, err = pcall(s.encode_tagged) @@ -87,6 +90,31 @@ local function test_tagged(test, s) test:is(ret, "%TAG !push! "..prefix.."\n--- 300\n...\n", "encode_tagged usage") ret = s.encode_tagged({handle = '!print!', prefix = prefix}, {a = 100, b = 200}) test:is(ret, "%TAG !print! tag:tarantool.io/push,2018\n---\na: 100\nb: 200\n...\n", 'encode_tagged usage') + -- + -- Test decoding tags. + -- + must_be_err = "Usage: decode_tag(<string>)" + ok, err = pcall(s.decode_tag) + test:is(err, must_be_err, "decode_tag usage") + ok, err = pcall(s.decode_tag, false) + test:is(err, must_be_err, "decode_tag usage") + local handle, prefix = s.decode_tag(ret) + test:is(handle, "!print!", "handle is decoded ok") + test:is(prefix, "tag:tarantool.io/push,2018", "prefix is decoded ok") + local several_tags = +[[%TAG !tag1! tag:tarantool.io/tag1,2018 +%TAG !tag2! tag:tarantool.io/tag2,2018 +--- +- 100 +... +]] + ok, err = s.decode_tag(several_tags) + test:is(ok, nil, "can not decode multiple tags") + test:is(err, "can not decode multiple tags", "same") + local no_tags = s.encode(100) + handle, prefix = s.decode_tag(no_tags) + test:is(handle, nil, "no tag - no handle") + test:is(prefix, nil, "no tag - no prefix") end tap.test("yaml", function(test) diff --git a/third_party/lua-yaml/lyaml.cc b/third_party/lua-yaml/lyaml.cc index 8329f84e9..d24715edd 100644 --- a/third_party/lua-yaml/lyaml.cc +++ b/third_party/lua-yaml/lyaml.cc @@ -361,6 +361,72 @@ static int l_load(lua_State *L) { return loader.document_count; } +/** + * Decode a global tag of document. Multiple tags can not be + * decoded. In a case of multiple documents only first is + * processed. + * @param YAML document in string. + * @retval nil, err Error occured during decoding. In the second + * value is error description. + * @retval nil, nil A document does not contain tags. + * @retval handle, prefix Handle and prefix of a tag. + */ +static int +l_load_tag(struct lua_State *L) +{ + if (lua_gettop(L) != 1 || !lua_isstring(L, 1)) + return luaL_error(L, "Usage: decode_tag(<string>)"); + size_t len; + const char *str = lua_tolstring(L, 1, &len); + struct lua_yaml_loader loader; + memset(&loader, 0, sizeof(loader)); + loader.L = L; + loader.cfg = luaL_checkserializer(L); + if (yaml_parser_initialize(&loader.parser) == 0) + luaL_error(L, OOM_ERRMSG); + yaml_tag_directive_t *start, *end; + yaml_parser_set_input_string(&loader.parser, (const unsigned char *) str, + len); + /* Initial parser step. Detect the documents start position. */ + if (do_parse(&loader) == 0) + goto parse_error; + if (loader.event.type != YAML_STREAM_START_EVENT) { + lua_pushnil(L); + lua_pushstring(L, "expected STREAM_START_EVENT"); + return 2; + } + /* Parse a document start. */ + if (do_parse(&loader) == 0) + goto parse_error; + if (loader.event.type == YAML_STREAM_END_EVENT) + goto no_tags; + assert(loader.event.type == YAML_DOCUMENT_START_EVENT); + start = loader.event.data.document_start.tag_directives.start; + end = loader.event.data.document_start.tag_directives.end; + if (start == end) + goto no_tags; + if (end - start > 1) { + lua_pushnil(L); + lua_pushstring(L, "can not decode multiple tags"); + return 2; + } + lua_pushstring(L, (const char *) start->handle); + lua_pushstring(L, (const char *) start->prefix); + delete_event(&loader); + yaml_parser_delete(&loader.parser); + return 2; + +parse_error: + lua_pushnil(L); + /* Make nil be before an error message. */ + lua_insert(L, -2); + return 2; + +no_tags: + lua_pushnil(L); + return 1; +} + static int dump_node(struct lua_yaml_dumper *dumper); static yaml_char_t *get_yaml_anchor(struct lua_yaml_dumper *dumper) { @@ -753,6 +819,7 @@ static const luaL_Reg yamllib[] = { { "encode", l_dump }, { "encode_tagged", l_dump_tagged }, { "decode", l_load }, + { "decode_tag", l_load_tag }, { "new", l_new }, { NULL, NULL} }; -- 2.15.1 (Apple Git-101)
next prev parent reply other threads:[~2018-04-20 13:24 UTC|newest] Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top 2018-04-20 13:24 [PATCH v2 00/10] session: introduce box.session.push Vladislav Shpilevoy 2018-04-20 13:24 ` [PATCH v2 01/10] yaml: don't throw OOM on any error in yaml encoding Vladislav Shpilevoy 2018-05-10 18:10 ` [tarantool-patches] " Konstantin Osipov 2018-04-20 13:24 ` [tarantool-patches] [PATCH v2 10/10] session: introduce binary box.session.push Vladislav Shpilevoy 2018-05-10 19:50 ` Konstantin Osipov 2018-05-24 20:50 ` [tarantool-patches] " Vladislav Shpilevoy 2018-04-20 13:24 ` [PATCH v2 02/10] yaml: introduce yaml.encode_tagged Vladislav Shpilevoy 2018-05-10 18:22 ` [tarantool-patches] " Konstantin Osipov 2018-05-24 20:50 ` [tarantool-patches] " Vladislav Shpilevoy 2018-05-30 19:15 ` Konstantin Osipov 2018-05-30 20:49 ` Vladislav Shpilevoy 2018-05-31 10:46 ` Konstantin Osipov 2018-04-20 13:24 ` Vladislav Shpilevoy [this message] 2018-05-10 18:41 ` [tarantool-patches] [PATCH v2 03/10] yaml: introduce yaml.decode_tag Konstantin Osipov 2018-05-24 20:50 ` [tarantool-patches] " Vladislav Shpilevoy 2018-05-31 10:54 ` Konstantin Osipov 2018-05-31 11:36 ` Konstantin Osipov 2018-04-20 13:24 ` [PATCH v2 04/10] console: use Lua C API to do formatting for console Vladislav Shpilevoy 2018-05-10 18:46 ` [tarantool-patches] " Konstantin Osipov 2018-05-24 20:50 ` [tarantool-patches] " Vladislav Shpilevoy 2018-04-20 13:24 ` [PATCH v2 05/10] session: move salt into iproto connection Vladislav Shpilevoy 2018-05-10 18:47 ` [tarantool-patches] " Konstantin Osipov 2018-04-20 13:24 ` [PATCH v2 06/10] session: introduce session vtab and meta Vladislav Shpilevoy 2018-05-10 19:20 ` [tarantool-patches] " Konstantin Osipov 2018-05-24 20:50 ` [tarantool-patches] " Vladislav Shpilevoy 2018-04-20 13:24 ` [PATCH v2 07/10] port: rename dump() into dump_msgpack() Vladislav Shpilevoy 2018-05-10 19:21 ` [tarantool-patches] " Konstantin Osipov 2018-04-20 13:24 ` [PATCH v2 08/10] session: introduce text box.session.push Vladislav Shpilevoy 2018-05-10 19:27 ` [tarantool-patches] " Konstantin Osipov 2018-05-24 20:50 ` [tarantool-patches] " Vladislav Shpilevoy 2018-04-20 13:24 ` [PATCH v2 09/10] session: enable box.session.push in local console Vladislav Shpilevoy 2018-05-10 19:28 ` [tarantool-patches] " Konstantin Osipov 2018-05-24 20:50 ` [tarantool-patches] [PATCH 1/1] netbox: introduce iterable future objects Vladislav Shpilevoy 2018-06-04 22:17 ` [tarantool-patches] " Vladislav Shpilevoy
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=0bce785538bba5d81f6c813732a7e309a941e175.1524228894.git.v.shpilevoy@tarantool.org \ --to=v.shpilevoy@tarantool.org \ --cc=tarantool-patches@freelists.org \ --cc=vdavydov.dev@gmail.com \ --subject='Re: [PATCH v2 03/10] yaml: introduce yaml.decode_tag' \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox