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
next prev parent 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