From 315a2d8683dc632ed976c11506098eb8ce511e5b Mon Sep 17 00:00:00 2001 From: Alexey Melnichuk Date: Sat, 3 Nov 2018 13:24:03 +0300 Subject: [PATCH 1/7] Add. URL errors --- src/lcerr_url.h | 20 ++++++++++++++++++++ src/lcerror.c | 26 ++++++++++++++++++++++++++ src/lcerror.h | 1 + 3 files changed, 47 insertions(+) create mode 100644 src/lcerr_url.h diff --git a/src/lcerr_url.h b/src/lcerr_url.h new file mode 100644 index 0000000..f1002a1 --- /dev/null +++ b/src/lcerr_url.h @@ -0,0 +1,20 @@ +#if LCURL_CURL_VER_GE(7,61,0) +ERR_ENTRY ( BAD_HANDLE ) +ERR_ENTRY ( BAD_PARTPOINTER ) +ERR_ENTRY ( BAD_PORT_NUMBER ) +ERR_ENTRY ( MALFORMED_INPUT ) +ERR_ENTRY ( NO_FRAGMENT ) +ERR_ENTRY ( NO_HOST ) +ERR_ENTRY ( NO_OPTIONS ) +ERR_ENTRY ( NO_PASSWORD ) +ERR_ENTRY ( NO_PORT ) +ERR_ENTRY ( NO_QUERY ) +ERR_ENTRY ( NO_SCHEME ) +ERR_ENTRY ( NO_USER ) +ERR_ENTRY ( OK ) +ERR_ENTRY ( OUT_OF_MEMORY ) +ERR_ENTRY ( UNKNOWN_PART ) +ERR_ENTRY ( UNSUPPORTED_SCHEME) +ERR_ENTRY ( URLDECODE ) +ERR_ENTRY ( USER_NOT_ALLOWED ) +#endif \ No newline at end of file diff --git a/src/lcerror.c b/src/lcerror.c index a130d9f..71e707e 100644 --- a/src/lcerror.c +++ b/src/lcerror.c @@ -20,6 +20,7 @@ static const char *LCURL_ERROR = LCURL_ERROR_NAME; #define LCURL_ERROR_MULTI_NAME "CURL-MULTI" #define LCURL_ERROR_SHARE_NAME "CURL-SHARE" #define LCURL_ERROR_FORM_NAME "CURL-FORM" +#define LCURL_ERROR_URL_NAME "CURL-URL" typedef struct lcurl_error_tag{ int tp; @@ -72,12 +73,24 @@ static const char* lcurl_err_form_mnemo(int err){ #undef ERR_ENTRY } +static const char* lcurl_err_url_mnemo(int err){ +#define ERR_ENTRY(E) case CURLUE_##E: return #E; + + switch (err){ + #include "lcerr_url.h" + } + return "UNKNOWN"; + +#undef ERR_ENTRY +} + static const char* _lcurl_err_mnemo(int tp, int err){ switch(tp){ case LCURL_ERROR_EASY : return lcurl_err_easy_mnemo (err); case LCURL_ERROR_MULTI: return lcurl_err_multi_mnemo(err); case LCURL_ERROR_SHARE: return lcurl_err_share_mnemo(err); case LCURL_ERROR_FORM : return lcurl_err_form_mnemo (err); + case LCURL_ERROR_URL : return lcurl_err_url_mnemo (err); } assert(0); return ""; @@ -89,6 +102,7 @@ static const char* _lcurl_err_msg(int tp, int err){ case LCURL_ERROR_MULTI: return curl_multi_strerror(err); case LCURL_ERROR_SHARE: return curl_share_strerror(err); case LCURL_ERROR_FORM : return lcurl_err_form_mnemo(err); + case LCURL_ERROR_URL : return lcurl_err_url_mnemo(err); } assert(0); return ""; @@ -100,6 +114,7 @@ static const char* _lcurl_err_category_name(int tp){ (tp == LCURL_ERROR_MULTI) || (tp == LCURL_ERROR_SHARE) || (tp == LCURL_ERROR_FORM ) || + (tp == LCURL_ERROR_URL ) || 0 ); @@ -120,6 +135,10 @@ static const char* _lcurl_err_category_name(int tp){ static const char *name = LCURL_ERROR_FORM_NAME; return name; } + case LCURL_ERROR_URL: { + static const char *name = LCURL_ERROR_URL_NAME; + return name; + } } assert(0); @@ -147,6 +166,7 @@ int lcurl_error_create(lua_State *L, int error_type, int no){ (error_type == LCURL_ERROR_MULTI) || (error_type == LCURL_ERROR_SHARE) || (error_type == LCURL_ERROR_FORM ) || + (error_type == LCURL_ERROR_URL ) || 0 ); @@ -233,6 +253,7 @@ static const int ERROR_CATEGORIES[] = { LCURL_ERROR_MULTI, LCURL_ERROR_SHARE, LCURL_ERROR_FORM, + LCURL_ERROR_URL, }; static const char* ERROR_CATEGORIES_NAME[] = { @@ -240,6 +261,7 @@ static const char* ERROR_CATEGORIES_NAME[] = { LCURL_ERROR_MULTI_NAME, LCURL_ERROR_SHARE_NAME, LCURL_ERROR_FORM_NAME, + LCURL_ERROR_URL_NAME, NULL }; @@ -297,6 +319,10 @@ static const lcurl_const_t lcurl_error_codes[] = { #define ERR_ENTRY(N) { "E_FORM_"#N, CURL_FORMADD_##N }, #include "lcerr_form.h" +#undef ERR_ENTRY + +#define ERR_ENTRY(N) { "E_URL_"#N, CURLUE_##N }, +#include "lcerr_url.h" #undef ERR_ENTRY {NULL, 0} diff --git a/src/lcerror.h b/src/lcerror.h index 44130ad..9ff2228 100644 --- a/src/lcerror.h +++ b/src/lcerror.h @@ -18,6 +18,7 @@ #define LCURL_ERROR_MULTI 2 #define LCURL_ERROR_SHARE 3 #define LCURL_ERROR_FORM 4 +#define LCURL_ERROR_URL 5 #define LCURL_ERROR_RETURN 1 #define LCURL_ERROR_RAISE 2 From 099f748bbb3b0c53d9864423976f60a3b83f2736 Mon Sep 17 00:00:00 2001 From: Alexey Melnichuk Date: Sun, 4 Nov 2018 14:15:41 +0300 Subject: [PATCH 2/7] Add. cURL urlapi support --- lakefile | 1 + rockspecs/lua-curl-scm-0.rockspec | 7 +- src/lcopturl.h | 21 ++++ src/lcurl.c | 14 ++- src/lcurlapi.c | 198 ++++++++++++++++++++++++++++++ src/lcurlapi.h | 22 ++++ test/run.lua | 1 + test/test_urlapi.lua | 191 ++++++++++++++++++++++++++++ 8 files changed, 451 insertions(+), 4 deletions(-) create mode 100644 src/lcopturl.h create mode 100644 src/lcurlapi.c create mode 100644 src/lcurlapi.h create mode 100644 test/test_urlapi.lua diff --git a/lakefile b/lakefile index 55c77a0..aa83c99 100644 --- a/lakefile +++ b/lakefile @@ -35,6 +35,7 @@ target('test', install, function() run_test('test_mime.lua') run_test('test_multi_callback.lua') run_test('test_multi_nested_callback.lua') + run_test('test_urlapi.lua') if not test_summary() then quit("test fail") diff --git a/rockspecs/lua-curl-scm-0.rockspec b/rockspecs/lua-curl-scm-0.rockspec index 2f284a8..2bfa9ee 100644 --- a/rockspecs/lua-curl-scm-0.rockspec +++ b/rockspecs/lua-curl-scm-0.rockspec @@ -61,9 +61,10 @@ build = { lcurl = { sources = { - "src/l52util.c", "src/lceasy.c", "src/lcerror.c", - "src/lchttppost.c", "src/lcurl.c", "src/lcutils.c", - "src/lcmulti.c", "src/lcshare.c","src/lcmime.c", + "src/l52util.c", "src/lceasy.c", "src/lcerror.c", + "src/lchttppost.c", "src/lcurl.c", "src/lcutils.c", + "src/lcmulti.c", "src/lcshare.c", "src/lcmime.c", + "src/lcurlapi.c", }, incdirs = { "$(CURL_INCDIR)" }, libdirs = { "$(CURL_LIBDIR)" } diff --git a/src/lcopturl.h b/src/lcopturl.h new file mode 100644 index 0000000..f076cc6 --- /dev/null +++ b/src/lcopturl.h @@ -0,0 +1,21 @@ +ENTRY_PART(fragment, UPART_FRAGMENT , CURLUE_NO_FRAGMENT ) +ENTRY_PART(host, UPART_HOST , CURLUE_NO_HOST ) +ENTRY_PART(options, UPART_OPTIONS , CURLUE_NO_OPTIONS ) +ENTRY_PART(password, UPART_PASSWORD , CURLUE_NO_PASSWORD ) +ENTRY_PART(path, UPART_PATH , CURLUE_OK ) +ENTRY_PART(port, UPART_PORT , CURLUE_NO_PORT ) +ENTRY_PART(query, UPART_QUERY , CURLUE_NO_QUERY ) +ENTRY_PART(scheme, UPART_SCHEME , CURLUE_NO_SCHEME ) +ENTRY_PART(url, UPART_URL , CURLUE_OK ) +ENTRY_PART(user, UPART_USER , CURLUE_NO_USER ) + +ENTRY_FLAG(DEFAULT_PORT ) +ENTRY_FLAG(NO_DEFAULT_PORT ) +ENTRY_FLAG(DEFAULT_SCHEME ) +ENTRY_FLAG(NON_SUPPORT_SCHEME ) +ENTRY_FLAG(PATH_AS_IS ) +ENTRY_FLAG(DISALLOW_USER ) +ENTRY_FLAG(URLDECODE ) +ENTRY_FLAG(URLENCODE ) +ENTRY_FLAG(APPENDQUERY ) +ENTRY_FLAG(GUESS_SCHEME ) diff --git a/src/lcurl.c b/src/lcurl.c index 507b0ee..a295e40 100644 --- a/src/lcurl.c +++ b/src/lcurl.c @@ -15,6 +15,7 @@ #include "lcerror.h" #include "lchttppost.h" #include "lcmime.h" +#include "lcurlapi.h" #include "lcutils.h" /*export*/ @@ -36,10 +37,14 @@ static int lcurl_share_new_safe(lua_State *L){ return lcurl_share_create(L, LCURL_ERROR_RETURN); } -static int lcurl_hpost_new_safe(lua_State *L){ +static int lcurl_hpost_new_safe(lua_State *L) { return lcurl_hpost_create(L, LCURL_ERROR_RETURN); } +static int lcurl_url_new_safe(lua_State *L) { + return lcurl_url_create(L, LCURL_ERROR_RETURN); +} + static int lcurl_easy_new(lua_State *L){ return lcurl_easy_create(L, LCURL_ERROR_RAISE); } @@ -56,6 +61,10 @@ static int lcurl_hpost_new(lua_State *L){ return lcurl_hpost_create(L, LCURL_ERROR_RAISE); } +static int lcurl_url_new(lua_State *L) { + return lcurl_url_create(L, LCURL_ERROR_RAISE); +} + static int lcurl_version(lua_State *L){ lua_pushstring(L, curl_version()); return 1; @@ -170,6 +179,7 @@ static const struct luaL_Reg lcurl_functions[] = { {"easy", lcurl_easy_new }, {"multi", lcurl_multi_new }, {"share", lcurl_share_new }, + {"url", lcurl_url_new }, {"version", lcurl_version }, {"version_info", lcurl_version_info }, @@ -182,6 +192,7 @@ static const struct luaL_Reg lcurl_functions_safe[] = { {"easy", lcurl_easy_new_safe }, {"multi", lcurl_multi_new_safe }, {"share", lcurl_share_new_safe }, + {"url", lcurl_url_new_safe }, {"version", lcurl_version }, {"version_info", lcurl_version_info }, @@ -258,6 +269,7 @@ static int luaopen_lcurl_(lua_State *L, const struct luaL_Reg *func){ LCURL_PUSH_NUP(L); lcurl_mime_initlib (L, NUP); LCURL_PUSH_NUP(L); lcurl_multi_initlib(L, NUP); LCURL_PUSH_NUP(L); lcurl_share_initlib(L, NUP); + LCURL_PUSH_NUP(L); lcurl_url_initlib (L, NUP); LCURL_PUSH_NUP(L); diff --git a/src/lcurlapi.c b/src/lcurlapi.c new file mode 100644 index 0000000..ea2d943 --- /dev/null +++ b/src/lcurlapi.c @@ -0,0 +1,198 @@ +/****************************************************************************** +* Author: Alexey Melnichuk +* +* Copyright (C) 2018 Alexey Melnichuk +* +* Licensed according to the included 'LICENSE' document +* +* This file is part of lua-lcurl library. +******************************************************************************/ + +#include "lcurlapi.h" +#include "lcurl.h" +#include "lcerror.h" +#include "lcutils.h" +#include + +#define LCURL_URL_NAME LCURL_PREFIX" URL" +static const char *LCURL_URL = LCURL_URL_NAME; + +#if LCURL_CURL_VER_GE(7,62,0) + +#define lcurl_geturl(L) lcurl_geturl_at(L, 1) + +typedef struct lcurl_url_tag{ + CURLU *url; + + int storage; + int err_mode; +}lcurl_url_t; + +int lcurl_url_create(lua_State *L, int error_mode){ + lcurl_url_t *p; + + p = lutil_newudatap(L, lcurl_url_t, LCURL_URL); + + p->url = curl_url(); + if(!p->url) return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_URL, CURLUE_OUT_OF_MEMORY); + + p->err_mode = error_mode; + + if (lua_gettop(L) > 1) { + const char *url = luaL_checkstring(L, 1); + unsigned int flags = 0; + CURLUcode code; + + if (lua_gettop(L) > 2) { + flags = (unsigned int)lutil_optint64(L, 2, 0); + } + + code = curl_url_set(p->url, CURLUPART_URL, url, flags); + if (code != CURLUE_OK) { + return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_URL, code); + } + } + + return 1; +} + +static lcurl_url_t *lcurl_geturl_at(lua_State *L, int i){ + lcurl_url_t *p = (lcurl_url_t *)lutil_checkudatap (L, i, LCURL_URL); + luaL_argcheck (L, p != NULL, 1, LCURL_URL_NAME" object expected"); + return p; +} + +static int lcurl_url_cleanup(lua_State *L){ + lcurl_url_t *p = lcurl_geturl(L); + + if (p->url){ + curl_url_cleanup(p->url); + p->url = NULL; + } + + return 0; +} + +static int lcurl_url_dup(lua_State *L) { + lcurl_url_t *r = lcurl_geturl(L); + lcurl_url_t *p = lutil_newudatap(L, lcurl_url_t, LCURL_URL); + + p->url = curl_url_dup(r->url); + if (!p->url) return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_URL, CURLUE_OUT_OF_MEMORY); + + p->err_mode = r->err_mode; + + return 1; +} + +static int lcurl_url_set(lua_State *L, CURLUPart what){ + lcurl_url_t *p = lcurl_geturl(L); + CURLUcode code; + const char *part; + unsigned int flags = 0; + + luaL_argcheck(L, lua_type(L, 2) == LUA_TSTRING || lutil_is_null(L, 2), 2, "string expected"); + + part = lua_tostring(L, 2); + flags = (unsigned int)lutil_optint64(L, 3, 0); + + code = curl_url_set(p->url, what, part, flags); + if (code != CURLUE_OK) { + return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_URL, code); + } + + lua_settop(L, 1); + return 1; +} + +static int lcurl_url_get(lua_State *L, CURLUPart what, CURLUcode empty) { + lcurl_url_t *p = lcurl_geturl(L); + CURLUcode code; + char *part = NULL; + unsigned int flags = 0; + + flags = (unsigned int)lutil_optint64(L, 2, 0); + + code = curl_url_get(p->url, what, &part, flags); + if (code != CURLUE_OK) { + if (part) { + curl_free(part); + part = NULL; + } + + if (code != empty) { + return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_URL, code); + } + } + + if (part == NULL) { + lutil_push_null(L); + } + else { + lua_pushstring(L, part); + curl_free(part); + } + + return 1; +} + +#define ENTRY_PART(N, S, E) static int lcurl_url_set_##N(lua_State *L){\ + return lcurl_url_set(L, CURL##S);\ +} +#define ENTRY_FLAG(S) + +#include "lcopturl.h" + +#undef ENTRY_PART +#undef ENTRY_FLAG + +#define ENTRY_PART(N, S, E) static int lcurl_url_get_##N(lua_State *L){\ + return lcurl_url_get(L, CURL##S, E);\ +} +#define ENTRY_FLAG(S) + +#include "lcopturl.h" + +#undef ENTRY_PART +#undef ENTRY_FLAG + +static const struct luaL_Reg lcurl_url_methods[] = { + #define ENTRY_PART(N, S, E) { "set_"#N, lcurl_url_set_##N }, + #define ENTRY_FLAG(S) + #include "lcopturl.h" + #undef ENTRY_PART + #undef ENTRY_FLAG + + #define ENTRY_PART(N, S, E) { "get_"#N, lcurl_url_get_##N }, + #define ENTRY_FLAG(S) + #include "lcopturl.h" + #undef ENTRY_PART + #undef ENTRY_FLAG + + { "dup", lcurl_url_dup }, + { "cleanup", lcurl_url_cleanup }, + { "__gc", lcurl_url_cleanup }, + { "__tostring", lcurl_url_get_url }, + + { NULL,NULL } +}; + +static const lcurl_const_t lcurl_url_opt[] = { + #define ENTRY_PART(N, S, E) { #S, CURL##S }, + #define ENTRY_FLAG(S) { "U_"#S, CURLU_##S }, + #include "lcopturl.h" + #undef ENTRY_PART + #undef ENTRY_FLAG + {NULL, 0} +}; +#endif + +void lcurl_url_initlib(lua_State *L, int nup){ +#if LCURL_CURL_VER_GE(7,62,0) + if(!lutil_createmetap(L, LCURL_URL, lcurl_url_methods, nup)) + lua_pop(L, nup); + lua_pop(L, 1); + + lcurl_util_set_const(L, lcurl_url_opt); +#endif +} diff --git a/src/lcurlapi.h b/src/lcurlapi.h new file mode 100644 index 0000000..bdf358b --- /dev/null +++ b/src/lcurlapi.h @@ -0,0 +1,22 @@ +/****************************************************************************** +* Author: Alexey Melnichuk +* +* Copyright (C) 2018 Alexey Melnichuk +* +* Licensed according to the included 'LICENSE' document +* +* This file is part of lua-lcurl library. +******************************************************************************/ + +#ifndef _LURL_H_ +#define _LURL_H_ + +#include "lcurl.h" +#include "lcutils.h" +#include + +void lcurl_url_initlib(lua_State *L, int nup); + +int lcurl_url_create(lua_State *L, int error_mode); + +#endif \ No newline at end of file diff --git a/test/run.lua b/test/run.lua index e5feee2..65394be 100644 --- a/test/run.lua +++ b/test/run.lua @@ -29,5 +29,6 @@ require "test_easy" require "test_form" require "test_mime" require "test_curl" +require "test_urlapi" RUN() diff --git a/test/test_urlapi.lua b/test/test_urlapi.lua new file mode 100644 index 0000000..9749b0e --- /dev/null +++ b/test/test_urlapi.lua @@ -0,0 +1,191 @@ +local lunit, RUN = lunit do +RUN = lunit and function()end or function () + local res = lunit.run() + if res.errors + res.failed > 0 then + os.exit(-1) + end + return os.exit(0) +end +lunit = require "lunit" +end + +local _, luacov = pcall(require, "luacov") +local TEST_CASE = assert(lunit.TEST_CASE) +local skip = lunit.skip or function() end +local curl = require "cURL" +local scurl = require "cURL.safe" +local utils = require "utils" + +local tostring = tostring + +local ENABLE = true + +local _ENV = TEST_CASE'urlapi' if ENABLE then + +if not curl.E_URL_OK then skip('URL API avaliable since libcurl 7.62.0') else + +local it = setmetatable(_ENV or _M, {__call = function(self, describe, fn) + self["test " .. describe] = fn +end}) + +local url + +local function U(u) + url = assert_userdata(curl.url()) + assert_equal(url, url:set_url(u)) + return url +end + +function teardown() + if url then url:cleanup() end + url = nil +end + +it('should export falgs', function() + assert_number(curl.U_DEFAULT_PORT ) + assert_number(curl.U_NO_DEFAULT_PORT ) + assert_number(curl.U_DEFAULT_SCHEME ) + assert_number(curl.U_NON_SUPPORT_SCHEME ) + assert_number(curl.U_PATH_AS_IS ) + assert_number(curl.U_DISALLOW_USER ) + assert_number(curl.U_URLDECODE ) + assert_number(curl.U_URLENCODE ) + assert_number(curl.U_APPENDQUERY ) + assert_number(curl.U_GUESS_SCHEME ) +end) + +it('should export parts', function() + assert_number(curl.UPART_URL ) + assert_number(curl.UPART_SCHEME ) + assert_number(curl.UPART_USER ) + assert_number(curl.UPART_PASSWORD ) + assert_number(curl.UPART_OPTIONS ) + assert_number(curl.UPART_HOST ) + assert_number(curl.UPART_PORT ) + assert_number(curl.UPART_PATH ) + assert_number(curl.UPART_QUERY ) + assert_number(curl.UPART_FRAGMENT ) +end) + +it('should export methods', function() + url = curl.url() + assert_function(url.dup ) + assert_function(url.cleanup ) + + assert_function(url.set_url ) + assert_function(url.set_scheme ) + assert_function(url.set_user ) + assert_function(url.set_password ) + assert_function(url.set_options ) + assert_function(url.set_host ) + assert_function(url.set_port ) + assert_function(url.set_path ) + assert_function(url.set_query ) + assert_function(url.set_fragment ) + + assert_function(url.get_url ) + assert_function(url.get_scheme ) + assert_function(url.get_user ) + assert_function(url.get_password ) + assert_function(url.get_options ) + assert_function(url.get_host ) + assert_function(url.get_port ) + assert_function(url.get_path ) + assert_function(url.get_query ) + assert_function(url.get_fragment ) +end) + +it('create and cleanup', function() + url = assert_userdata(curl.url()) + assert_nil(url:cleanup()) +end) + +it('constructor with parameters', function() + url = assert_userdata(curl.url('http://example.com/')) + assert_equal('http://example.com/', url:get_url()) + + url = assert_userdata(curl.url('example.com', curl.U_GUESS_SCHEME)) + assert_equal('http://example.com/', url:get_url()) +end) + +it('dup url', function() + url = assert_userdata(curl.url('http://example.com/')) + local u2 = url:dup() + assert_not_equal(url, u2) + assert_equal('http://example.com/', u2:get_url()) + assert_equal('http://example.com/', url:get_url()) + url:cleanup() + url = u2 + assert_equal('http://example.com/', url:get_url()) +end) + +it('should convert to string', function() + assert_equal('http://example.com/', tostring(U"http://example.com/")) +end) + +it('should decode url', function() + url = U"http://example.com" + assert_equal('http', url:get_scheme()) + assert_equal('example.com', url:get_host()) + assert_equal('/', url:get_path()) +end) + +it('should cast scheme to lower case', function() + url = U"HTTP://Example.com" + assert_equal('http', url:get_scheme()) + assert_equal('Example.com', url:get_host()) + assert_equal('/', url:get_path()) + assert_equal("http://Example.com/", url:get_url()) +end) + +it('should append query', function() + url = U"http://example.com" + assert_equal(url, url:set_query("a=hello world", curl.U_APPENDQUERY + curl.U_URLENCODE)) + assert_equal(url, url:set_query("b=A&B", curl.U_APPENDQUERY + curl.U_URLENCODE)) + assert_equal("http://example.com/?a=hello+world&b=A%26B", url:get_url()) +end) + +it('should append only one parameter in query per call', function() + url = U"http://example.com" + assert_equal(url, url:set_query("a=hello world&b=A&B", curl.U_APPENDQUERY + curl.U_URLENCODE)) + assert_equal("http://example.com/?a=hello+world%26b=A%26B", url:get_url()) +end) + +it('should set encoded query', function() + url = U("http://example.com/?a=hello world&b=d") + assert_equal('a=hello world&b=d', url:get_query()) +end) + +it('should returns NULL as empty value', function() + url = curl.url() + assert_equal(curl.null, url:get_query()) + assert_equal(curl.null, url:get_host()) + assert_equal(curl.null, url:get_port()) + assert_equal(curl.null, url:get_password()) + assert_equal(curl.null, url:get_scheme()) + assert_equal(curl.null, url:get_options()) + assert_equal(curl.null, url:get_fragment()) + + assert_equal('/', url:get_path()) +end) + +it('should returns nil and error for invalid url in safe mode', function() + url = scurl.url() + local _, err = assert_nil(url:get_url()) + assert_equal('CURL-URL', err:cat()) +end) + +it('should raise error for invalid url', function() + url = curl.url() + assert_error_match('CURL%-URL', function() url:get_url() end) +end) + +-- it('should set encoded query', function() +-- url = U"http://example.com" +-- assert_equal(url, url:set_query("a=hello world", curl.U_URLENCODE)) +-- assert_equal("http://example.com/?a=hello+world", url:get_url()) +-- end) + +end end + +RUN() From 9c0a6cc6265dcae9164ffb0e26d76c4e532077e2 Mon Sep 17 00:00:00 2001 From: Alexey Melnichuk Date: Sun, 4 Nov 2018 14:33:10 +0300 Subject: [PATCH 3/7] Fix. Use url api also for correct libcurl version --- src/lcurl.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/lcurl.c b/src/lcurl.c index a295e40..941ba14 100644 --- a/src/lcurl.c +++ b/src/lcurl.c @@ -41,10 +41,14 @@ static int lcurl_hpost_new_safe(lua_State *L) { return lcurl_hpost_create(L, LCURL_ERROR_RETURN); } +#if LCURL_CURL_VER_GE(7,62,0) + static int lcurl_url_new_safe(lua_State *L) { return lcurl_url_create(L, LCURL_ERROR_RETURN); } +#endif + static int lcurl_easy_new(lua_State *L){ return lcurl_easy_create(L, LCURL_ERROR_RAISE); } @@ -61,10 +65,14 @@ static int lcurl_hpost_new(lua_State *L){ return lcurl_hpost_create(L, LCURL_ERROR_RAISE); } +#if LCURL_CURL_VER_GE(7,62,0) + static int lcurl_url_new(lua_State *L) { return lcurl_url_create(L, LCURL_ERROR_RAISE); } +#endif + static int lcurl_version(lua_State *L){ lua_pushstring(L, curl_version()); return 1; @@ -179,7 +187,9 @@ static const struct luaL_Reg lcurl_functions[] = { {"easy", lcurl_easy_new }, {"multi", lcurl_multi_new }, {"share", lcurl_share_new }, +#if LCURL_CURL_VER_GE(7,62,0) {"url", lcurl_url_new }, +#endif {"version", lcurl_version }, {"version_info", lcurl_version_info }, @@ -192,7 +202,9 @@ static const struct luaL_Reg lcurl_functions_safe[] = { {"easy", lcurl_easy_new_safe }, {"multi", lcurl_multi_new_safe }, {"share", lcurl_share_new_safe }, +#if LCURL_CURL_VER_GE(7,62,0) {"url", lcurl_url_new_safe }, +#endif {"version", lcurl_version }, {"version_info", lcurl_version_info }, From 8046514220a2aebb98e5883c5965b8051a56e874 Mon Sep 17 00:00:00 2001 From: Alexey Melnichuk Date: Sun, 4 Nov 2018 14:38:41 +0300 Subject: [PATCH 4/7] Fix. init urlapi module on old versions --- src/lcurlapi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lcurlapi.c b/src/lcurlapi.c index ea2d943..76ceede 100644 --- a/src/lcurlapi.c +++ b/src/lcurlapi.c @@ -194,5 +194,7 @@ void lcurl_url_initlib(lua_State *L, int nup){ lua_pop(L, 1); lcurl_util_set_const(L, lcurl_url_opt); +#else + lua_pop(L, nup); #endif } From 474135372e12eeb48fd014eca01c55a00015fd31 Mon Sep 17 00:00:00 2001 From: Alexey Melnichuk Date: Sun, 4 Nov 2018 18:24:47 +0300 Subject: [PATCH 5/7] Update test --- test/test_urlapi.lua | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/test_urlapi.lua b/test/test_urlapi.lua index 9749b0e..7230327 100644 --- a/test/test_urlapi.lua +++ b/test/test_urlapi.lua @@ -16,13 +16,15 @@ local curl = require "cURL" local scurl = require "cURL.safe" local utils = require "utils" -local tostring = tostring +local tostring, pcall = tostring, pcall + +local function skip_case(msg) return function() skip(msg) end end local ENABLE = true local _ENV = TEST_CASE'urlapi' if ENABLE then -if not curl.E_URL_OK then skip('URL API avaliable since libcurl 7.62.0') else +if not curl.E_URL_OK then test = skip_case('URL API avaliable since libcurl 7.62.0') else local it = setmetatable(_ENV or _M, {__call = function(self, describe, fn) self["test " .. describe] = fn @@ -177,7 +179,8 @@ end) it('should raise error for invalid url', function() url = curl.url() - assert_error_match('CURL%-URL', function() url:get_url() end) + local _, err = assert_false(pcall(url.get_url, url)) + assert_match('CURL%-URL', tostring(err)) end) -- it('should set encoded query', function() From ce1be595caaef917a72962b83945957f3cfd9511 Mon Sep 17 00:00:00 2001 From: Alexey Melnichuk Date: Sun, 4 Nov 2018 19:15:35 +0300 Subject: [PATCH 6/7] Fix. tostring metamethod have to return string or raise error --- src/lcurlapi.c | 27 ++++++++++++++++++++++++++- test/test_urlapi.lua | 12 ++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/lcurlapi.c b/src/lcurlapi.c index 76ceede..f4cb905 100644 --- a/src/lcurlapi.c +++ b/src/lcurlapi.c @@ -136,6 +136,31 @@ static int lcurl_url_get(lua_State *L, CURLUPart what, CURLUcode empty) { return 1; } +static int lcurl_url_to_s(lua_State *L) { + lcurl_url_t *p = lcurl_geturl(L); + char *part = NULL; + + CURLUcode code = curl_url_get(p->url, CURLUPART_URL, &part, 0); + + if (code != CURLUE_OK) { + if (part) { + curl_free(part); + } + + return lcurl_fail_ex(L, LCURL_ERROR_RAISE, LCURL_ERROR_URL, code); + } + + if (part == NULL) { + lua_pushliteral(L, ""); + } + else { + lua_pushstring(L, part); + curl_free(part); + } + + return 1; +} + #define ENTRY_PART(N, S, E) static int lcurl_url_set_##N(lua_State *L){\ return lcurl_url_set(L, CURL##S);\ } @@ -172,7 +197,7 @@ static const struct luaL_Reg lcurl_url_methods[] = { { "dup", lcurl_url_dup }, { "cleanup", lcurl_url_cleanup }, { "__gc", lcurl_url_cleanup }, - { "__tostring", lcurl_url_get_url }, + { "__tostring", lcurl_url_to_s }, { NULL,NULL } }; diff --git a/test/test_urlapi.lua b/test/test_urlapi.lua index 7230327..bbba08b 100644 --- a/test/test_urlapi.lua +++ b/test/test_urlapi.lua @@ -183,6 +183,18 @@ it('should raise error for invalid url', function() assert_match('CURL%-URL', tostring(err)) end) +it('should raise error for tostring', function() + url = curl.url() + local _, err = assert_false(pcall(tostring, url)) + assert_match('CURL%-URL', tostring(err)) +end) + +it('should raise error for tostring in safe mode', function() + url = scurl.url() + local _, err = assert_false(pcall(tostring, url)) + assert_match('CURL%-URL', tostring(err)) +end) + -- it('should set encoded query', function() -- url = U"http://example.com" -- assert_equal(url, url:set_query("a=hello world", curl.U_URLENCODE)) From 949493b924f8636f6636c08c4e925a5040a05f1b Mon Sep 17 00:00:00 2001 From: Alexey Melnichuk Date: Mon, 5 Nov 2018 11:59:29 +0300 Subject: [PATCH 7/7] Remove unused var from url struct. --- src/lcurlapi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lcurlapi.c b/src/lcurlapi.c index f4cb905..a0f5f51 100644 --- a/src/lcurlapi.c +++ b/src/lcurlapi.c @@ -24,7 +24,6 @@ static const char *LCURL_URL = LCURL_URL_NAME; typedef struct lcurl_url_tag{ CURLU *url; - int storage; int err_mode; }lcurl_url_t;