Tarantool development patches archive
 help / color / mirror / Atom feed
From: olegrok@tarantool.org
To: tarantool-patches@dev.tarantool.org, alexander.turenko@tarantool.org
Cc: Oleg Babin <babinoleg@mail.ru>
Subject: [Tarantool-patches] [PATCH 1/2] httpc: introduce url_escape/url_unescape functions
Date: Thu,  9 Jan 2020 11:04:13 +0300	[thread overview]
Message-ID: <360e3a35ff40d3dce9c86f3856f24925bdb8b921.1577881257.git.babinoleg@mail.ru> (raw)
In-Reply-To: <cover.1577881257.git.babinoleg@mail.ru>

From: Oleg Babin <babinoleg@mail.ru>

cURL easy API contains functions curl_easy_escape and
curl_easy_unescape:

  - https://curl.haxx.se/libcurl/c/curl_easy_escape.html
  - https://curl.haxx.se/libcurl/c/curl_easy_unescape.html

This functions can be sometimes useful for our users
especially when they works with http client and form
query arguments for http request

This patch introduces two functions available from
our http client:
```lua
httpc.url_escape
httpc.url_unescape
```

Need for #3682
---
Issue: https://github.com/tarantool/tarantool/issues/3682
My related github PR: https://github.com/tarantool/tarantool/pull/4153
 src/httpc.c                       | 19 +++++++++++++
 src/httpc.h                       | 36 +++++++++++++++++++++++++
 src/lua/httpc.c                   | 45 +++++++++++++++++++++++++++++++
 src/lua/httpc.lua                 | 17 +++++++++---
 test/app-tap/http_client.test.lua | 21 ++++++++++++++-
 5 files changed, 134 insertions(+), 4 deletions(-)

diff --git a/src/httpc.c b/src/httpc.c
index be73e3684..d152275e3 100644
--- a/src/httpc.c
+++ b/src/httpc.c
@@ -467,3 +467,22 @@ httpc_execute(struct httpc_request *req, double timeout)
 
 	return 0;
 }
+
+char *
+httpc_str_escape(struct httpc_env *env, const char *str, int len)
+{
+	return curl_easy_escape(env->curl_env.multi, str, len);
+}
+
+char *
+httpc_str_unescape(struct httpc_env *env, const char *str, int len,
+		int *outlen)
+{
+	return curl_easy_unescape(env->curl_env.multi, str, len, outlen);
+}
+
+void
+httpc_str_free(char *str)
+{
+	curl_free(str);
+}
diff --git a/src/httpc.h b/src/httpc.h
index 94d543a40..22a83f72c 100644
--- a/src/httpc.h
+++ b/src/httpc.h
@@ -413,4 +413,40 @@ httpc_execute(struct httpc_request *req, double timeout);
 
 /** Request }}} */
 
+/** {{{ Encode/Decode */
+
+/**
+ * This function URL encodes the given string
+ * according RFC3986
+ * @param req - reference to request object with filled fields
+ * @param str - input string to be encoded
+ * @param len - length of input string
+ * @return encoded string or NULL
+ */
+char *
+httpc_str_escape(struct httpc_env *env, const char *str, int len);
+
+/**
+ * This function URL decodes the given string
+ * according RFC3986
+ * @param req - reference to request object with filled fields
+ * @param str - input string to be encoded
+ * @param len - length of input string
+ * @param outlen - - length of output string
+ * @return decoded string or NULL
+ */
+
+char *
+httpc_str_unescape(struct httpc_env *env, const char *str, int len, int *outlen);
+
+/**
+ * This function reclaims memory that has been obtained
+ * through a libcurl call
+ * @param str - pointer to string returned from escape/unescape
+ */
+void
+httpc_str_free(char *str);
+
+/** Encode/Decode }}} */
+
 #endif /* TARANTOOL_HTTPC_H_INCLUDED */
diff --git a/src/lua/httpc.c b/src/lua/httpc.c
index c3dd611fa..e0c55f49e 100644
--- a/src/lua/httpc.c
+++ b/src/lua/httpc.c
@@ -425,6 +425,49 @@ luaT_httpc_cleanup(lua_State *L)
 	return 2;
 }
 
+static int
+luaT_httpc_escape(lua_State *L)
+{
+	struct httpc_env *ctx = luaT_httpc_checkenv(L);
+	if (ctx == NULL)
+		return luaL_error(L, "can't get httpc environment");
+
+	size_t str_len;
+	const char *str = luaL_checklstring(L, 2, &str_len);
+	if (str == NULL)
+		return luaL_error(L, "second argument should be a string");
+
+	char *outstr = httpc_str_escape(ctx, str, str_len);
+	if (outstr == NULL)
+		return luaL_error(L, "string escaping error");
+
+	lua_pushstring(L, outstr);
+	httpc_str_free(outstr);
+	return 1;
+}
+
+static int
+luaT_httpc_unescape(lua_State *L)
+{
+	struct httpc_env *ctx = luaT_httpc_checkenv(L);
+	if (ctx == NULL)
+		return luaL_error(L, "can't get httpc environment");
+
+	size_t str_len;
+	const char *str = luaL_checklstring(L, 2, &str_len);
+	if (str == NULL)
+		return luaL_error(L, "second argument should be a string");
+
+	int outstr_len;
+	char *outstr = httpc_str_unescape(ctx, str, str_len, &outstr_len);
+	if (outstr == NULL)
+		return luaL_error(L, "string unescaping error");
+
+	lua_pushlstring(L, outstr, outstr_len);
+	httpc_str_free(outstr);
+	return 1;
+}
+
 /*
  * }}}
  */
@@ -435,6 +478,8 @@ luaT_httpc_cleanup(lua_State *L)
 
 static const struct luaL_Reg Module[] = {
 	{"new", luaT_httpc_new},
+	{"escape", luaT_httpc_escape},
+	{"unescape", luaT_httpc_unescape},
 	{NULL, NULL}
 };
 
diff --git a/src/lua/httpc.lua b/src/lua/httpc.lua
index 6381c6a1a..33cb78f3c 100644
--- a/src/lua/httpc.lua
+++ b/src/lua/httpc.lua
@@ -29,8 +29,6 @@
 --  SUCH DAMAGE.
 --
 
-local fiber = require('fiber')
-
 local driver = package.loaded.http.client
 package.loaded.http = nil
 
@@ -442,7 +440,20 @@ curl_mt = {
 -- Export
 --
 local http_default = http_new()
-local this_module = { new = http_new, }
+
+local function url_escape(str)
+    return driver.escape(http_default.curl, str)
+end
+
+local function url_unescape(str)
+    return driver.unescape(http_default.curl, str)
+end
+
+local this_module = {
+    new = http_new,
+    url_escape = url_escape,
+    url_unescape = url_unescape
+}
 
 local function http_default_wrap(fname)
     return function(...) return http_default[fname](http_default, ...) end
diff --git a/test/app-tap/http_client.test.lua b/test/app-tap/http_client.test.lua
index b85b605cf..3676f56b4 100755
--- a/test/app-tap/http_client.test.lua
+++ b/test/app-tap/http_client.test.lua
@@ -611,7 +611,7 @@ function run_tests(test, sock_family, sock_addr)
     stop_server(test, server)
 end
 
-test:plan(2)
+test:plan(3)
 
 test:test("http over AF_INET", function(test)
     local s = socketlib('AF_INET', 'SOCK_STREAM', 0)
@@ -634,4 +634,23 @@ test:test("http over AF_UNIX", function(test)
     os.remove(path)
 end)
 
+test:test("url_escape/url_unescape", function(test)
+    test:plan(11)
+    test:is('hello', client.url_escape('hello'), 'correct encoding of eng')
+    test:is('%D0%BF%D1%80%D0%B8%D0%B2%D0%B5%D1%82', client.url_escape('привет'), 'correct encoding of rus')
+
+    test:is('hello', client.url_unescape('hello'), 'correct decoding of eng')
+    test:is('привет', client.url_unescape('%D0%BF%D1%80%D0%B8%D0%B2%D0%B5%D1%82'), 'correct decoding of rus')
+
+    test:is('hello', client.url_escape(client.url_unescape('hello')), 'decoding and encoding of "hello"')
+    test:is('привет', client.url_unescape(client.url_escape('привет')), 'encoding and decoding of "привет"')
+
+    test:is('%00', client.url_escape(client.url_unescape('%00')), 'decoding and encoding of %00')
+    test:is('\0', client.url_unescape(client.url_escape('\0')), 'encoding and decoding of \\0')
+
+    test:is('%20', client.url_escape(' '), 'space is escaped as %20')
+    test:is('%24%26%2B%2C%3A%3B%3D%3F%40', client.url_escape('$&+,:;=?@'), 'special characters escaping')
+    test:is('-._~', client.url_escape('-._~'), '-._~ are not escaped according RFC 3986')
+end)
+
 os.exit(test:check() == true and 0 or -1)
-- 
2.23.0

  reply	other threads:[~2020-01-09  8:04 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-01-09  8:04 [Tarantool-patches] [PATCH 0/2] Borrow encoding/decoding functions from cURL olegrok
2020-01-09  8:04 ` olegrok [this message]
2020-01-09  8:04 ` [Tarantool-patches] [PATCH 2/2] httpc: introduce format_query and parse_query functions olegrok

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=360e3a35ff40d3dce9c86f3856f24925bdb8b921.1577881257.git.babinoleg@mail.ru \
    --to=olegrok@tarantool.org \
    --cc=alexander.turenko@tarantool.org \
    --cc=babinoleg@mail.ru \
    --cc=tarantool-patches@dev.tarantool.org \
    --subject='Re: [Tarantool-patches] [PATCH 1/2] httpc: introduce url_escape/url_unescape functions' \
    /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