Tarantool development patches archive
 help / color / mirror / Atom feed
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)

  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