diff --git a/src/l52util.c b/src/l52util.c index 6373687..4d0feec 100644 --- a/src/l52util.c +++ b/src/l52util.c @@ -1,178 +1,182 @@ -/****************************************************************************** -* Author: Alexey Melnichuk -* -* Copyright (C) 2014-2021 Alexey Melnichuk -* -* Licensed according to the included 'LICENSE' document -* -* This file is part of Lua-cURL library. -******************************************************************************/ - -#include "l52util.h" - -#include -#include /* for memset */ -#include - -#if LUA_VERSION_NUM >= 502 - -int luaL_typerror (lua_State *L, int narg, const char *tname) { - const char *msg = lua_pushfstring(L, "%s expected, got %s", tname, - luaL_typename(L, narg)); - return luaL_argerror(L, narg, msg); -} - -#ifndef luaL_register - -void luaL_register (lua_State *L, const char *libname, const luaL_Reg *l){ - if(libname) lua_newtable(L); - luaL_setfuncs(L, l, 0); -} - -#endif - -#else - -void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup){ - luaL_checkstack(L, nup, "too many upvalues"); - for (; l->name != NULL; l++) { /* fill the table with given functions */ - int i; - for (i = 0; i < nup; i++) /* copy upvalues to the top */ - lua_pushvalue(L, -nup); - lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ - lua_setfield(L, -(nup + 2), l->name); - } - lua_pop(L, nup); /* remove upvalues */ -} - -void lua_rawgetp(lua_State *L, int index, const void *p){ - index = lua_absindex(L, index); - lua_pushlightuserdata(L, (void *)p); - lua_rawget(L, index); -} - -void lua_rawsetp (lua_State *L, int index, const void *p){ - index = lua_absindex(L, index); - lua_pushlightuserdata(L, (void *)p); - lua_insert(L, -2); - lua_rawset(L, index); -} - -#endif - -int lutil_newmetatablep (lua_State *L, const void *p) { - lua_rawgetp(L, LUA_REGISTRYINDEX, p); - if (!lua_isnil(L, -1)) /* name already in use? */ - return 0; /* leave previous value on top, but return 0 */ - lua_pop(L, 1); - - lua_newtable(L); /* create metatable */ - lua_pushvalue(L, -1); /* duplicate metatable to set*/ - - lua_pushliteral (L, "__type"); - lua_pushstring(L, p); // push meta name - lua_settable (L, -3); // set meta name - - lua_rawsetp(L, LUA_REGISTRYINDEX, p); - - return 1; -} - -void lutil_getmetatablep (lua_State *L, const void *p) { - lua_rawgetp(L, LUA_REGISTRYINDEX, p); -} - -void lutil_setmetatablep (lua_State *L, const void *p) { - lutil_getmetatablep(L, p); - assert(lua_istable(L,-1)); - lua_setmetatable (L, -2); -} - -int lutil_isudatap (lua_State *L, int ud, const void *p) { - if (lua_isuserdata(L, ud)){ - if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ - int res; - lutil_getmetatablep(L,p); /* get correct metatable */ - res = lua_rawequal(L, -1, -2); /* does it have the correct mt? */ - lua_pop(L, 2); /* remove both metatables */ - return res; - } - } - return 0; -} - -void *lutil_checkudatap (lua_State *L, int ud, const void *p) { - void *up = lua_touserdata(L, ud); - if (up != NULL) { /* value is a userdata? */ - if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ - lutil_getmetatablep(L,p); /* get correct metatable */ - if (lua_rawequal(L, -1, -2)) { /* does it have the correct mt? */ - lua_pop(L, 2); /* remove both metatables */ - return up; - } - } - } - luaL_typerror(L, ud, p); /* else error */ - return NULL; /* to avoid warnings */ -} - -int lutil_createmetap (lua_State *L, const void *p, const luaL_Reg *methods, int nup) { - if (!lutil_newmetatablep(L, p)){ - lua_insert(L, -1 - nup); /* move mt prior upvalues */ - return 0; - } - - lua_insert(L, -1 - nup); /* move mt prior upvalues */ - luaL_setfuncs (L, methods, nup); /* define methods */ - lua_pushliteral (L, "__index"); /* define metamethods */ - lua_pushvalue (L, -2); - lua_settable (L, -3); - return 1; -} - -void *lutil_newudatap_impl(lua_State *L, size_t size, const void *p){ - void *obj = lua_newuserdata (L, size); - memset(obj, 0, size); - lutil_setmetatablep(L, p); - return obj; -} - -void lutil_pushint64(lua_State *L, int64_t v){ - if(sizeof(lua_Integer) >= sizeof(int64_t)){ - lua_pushinteger(L, (lua_Integer)v); - return; - } - lua_pushnumber(L, (lua_Number)v); -} - -void lutil_pushuint(lua_State *L, unsigned int v){ -#if LUA_VERSION_NUM >= 503 - lua_pushinteger(L, (lua_Integer)v); -#else - lua_pushnumber(L, (lua_Number)v); -#endif -} - -int64_t lutil_checkint64(lua_State *L, int idx){ - if(sizeof(lua_Integer) >= sizeof(int64_t)) - return luaL_checkinteger(L, idx); - return (int64_t)luaL_checknumber(L, idx); -} - -int64_t lutil_optint64(lua_State *L, int idx, int64_t v){ - if(sizeof(lua_Integer) >= sizeof(int64_t)) - return luaL_optinteger(L, idx, v); - return (int64_t)luaL_optnumber(L, idx, v); -} - -void lutil_pushnvalues(lua_State *L, int n){ - for(;n;--n) lua_pushvalue(L, -n); -} - -int lutil_is_null(lua_State *L, int i){ - return lua_islightuserdata(L, i) && 0 == lua_touserdata(L, i); -} - -void lutil_push_null(lua_State *L){ - lua_pushlightuserdata(L, (void*)0); -} +/****************************************************************************** +* Author: Alexey Melnichuk +* +* Copyright (C) 2014-2021 Alexey Melnichuk +* +* Licensed according to the included 'LICENSE' document +* +* This file is part of Lua-cURL library. +******************************************************************************/ + +#include "l52util.h" + +#include +#include /* for memset */ +#include + +#if LUA_VERSION_NUM >= 502 + +int luaL_typerror (lua_State *L, int narg, const char *tname) { + const char *msg = lua_pushfstring(L, "%s expected, got %s", tname, + luaL_typename(L, narg)); + return luaL_argerror(L, narg, msg); +} + +#ifndef luaL_register + +void luaL_register (lua_State *L, const char *libname, const luaL_Reg *l){ + if(libname) lua_newtable(L); + luaL_setfuncs(L, l, 0); +} + +#endif + +#else + +#ifndef LUAJIT_VERSION_NUM + +void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup){ + luaL_checkstack(L, nup, "too many upvalues"); + for (; l->name != NULL; l++) { /* fill the table with given functions */ + int i; + for (i = 0; i < nup; i++) /* copy upvalues to the top */ + lua_pushvalue(L, -nup); + lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ + lua_setfield(L, -(nup + 2), l->name); + } + lua_pop(L, nup); /* remove upvalues */ +} + +#endif + +void lua_rawgetp(lua_State *L, int index, const void *p){ + index = lua_absindex(L, index); + lua_pushlightuserdata(L, (void *)p); + lua_rawget(L, index); +} + +void lua_rawsetp (lua_State *L, int index, const void *p){ + index = lua_absindex(L, index); + lua_pushlightuserdata(L, (void *)p); + lua_insert(L, -2); + lua_rawset(L, index); +} + +#endif + +int lutil_newmetatablep (lua_State *L, const void *p) { + lua_rawgetp(L, LUA_REGISTRYINDEX, p); + if (!lua_isnil(L, -1)) /* name already in use? */ + return 0; /* leave previous value on top, but return 0 */ + lua_pop(L, 1); + + lua_newtable(L); /* create metatable */ + lua_pushvalue(L, -1); /* duplicate metatable to set*/ + + lua_pushliteral (L, "__type"); + lua_pushstring(L, p); // push meta name + lua_settable (L, -3); // set meta name + + lua_rawsetp(L, LUA_REGISTRYINDEX, p); + + return 1; +} + +void lutil_getmetatablep (lua_State *L, const void *p) { + lua_rawgetp(L, LUA_REGISTRYINDEX, p); +} + +void lutil_setmetatablep (lua_State *L, const void *p) { + lutil_getmetatablep(L, p); + assert(lua_istable(L,-1)); + lua_setmetatable (L, -2); +} + +int lutil_isudatap (lua_State *L, int ud, const void *p) { + if (lua_isuserdata(L, ud)){ + if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ + int res; + lutil_getmetatablep(L,p); /* get correct metatable */ + res = lua_rawequal(L, -1, -2); /* does it have the correct mt? */ + lua_pop(L, 2); /* remove both metatables */ + return res; + } + } + return 0; +} + +void *lutil_checkudatap (lua_State *L, int ud, const void *p) { + void *up = lua_touserdata(L, ud); + if (up != NULL) { /* value is a userdata? */ + if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ + lutil_getmetatablep(L,p); /* get correct metatable */ + if (lua_rawequal(L, -1, -2)) { /* does it have the correct mt? */ + lua_pop(L, 2); /* remove both metatables */ + return up; + } + } + } + luaL_typerror(L, ud, p); /* else error */ + return NULL; /* to avoid warnings */ +} + +int lutil_createmetap (lua_State *L, const void *p, const luaL_Reg *methods, int nup) { + if (!lutil_newmetatablep(L, p)){ + lua_insert(L, -1 - nup); /* move mt prior upvalues */ + return 0; + } + + lua_insert(L, -1 - nup); /* move mt prior upvalues */ + luaL_setfuncs (L, methods, nup); /* define methods */ + lua_pushliteral (L, "__index"); /* define metamethods */ + lua_pushvalue (L, -2); + lua_settable (L, -3); + return 1; +} + +void *lutil_newudatap_impl(lua_State *L, size_t size, const void *p){ + void *obj = lua_newuserdata (L, size); + memset(obj, 0, size); + lutil_setmetatablep(L, p); + return obj; +} + +void lutil_pushint64(lua_State *L, int64_t v){ + if(sizeof(lua_Integer) >= sizeof(int64_t)){ + lua_pushinteger(L, (lua_Integer)v); + return; + } + lua_pushnumber(L, (lua_Number)v); +} + +void lutil_pushuint(lua_State *L, unsigned int v){ +#if LUA_VERSION_NUM >= 503 + lua_pushinteger(L, (lua_Integer)v); +#else + lua_pushnumber(L, (lua_Number)v); +#endif +} + +int64_t lutil_checkint64(lua_State *L, int idx){ + if(sizeof(lua_Integer) >= sizeof(int64_t)) + return luaL_checkinteger(L, idx); + return (int64_t)luaL_checknumber(L, idx); +} + +int64_t lutil_optint64(lua_State *L, int idx, int64_t v){ + if(sizeof(lua_Integer) >= sizeof(int64_t)) + return luaL_optinteger(L, idx, v); + return (int64_t)luaL_optnumber(L, idx, v); +} + +void lutil_pushnvalues(lua_State *L, int n){ + for(;n;--n) lua_pushvalue(L, -n); +} + +int lutil_is_null(lua_State *L, int i){ + return lua_islightuserdata(L, i) && 0 == lua_touserdata(L, i); +} + +void lutil_push_null(lua_State *L){ + lua_pushlightuserdata(L, (void*)0); +} diff --git a/src/l52util.h b/src/l52util.h index 97348a0..fe41d1a 100644 --- a/src/l52util.h +++ b/src/l52util.h @@ -65,7 +65,9 @@ void luaL_register (lua_State *L, const char *libname, const luaL_Reg *l); void lua_rawgetp (lua_State *L, int index, const void *p); void lua_rawsetp (lua_State *L, int index, const void *p); +#ifndef LUAJIT_VERSION_NUM void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup); +#endif #endif diff --git a/src/lceasy.c b/src/lceasy.c index ad48022..4fc4c78 100644 --- a/src/lceasy.c +++ b/src/lceasy.c @@ -130,7 +130,7 @@ static int lcurl_easy_to_s(lua_State *L){ return 1; } -static int lcurl_easy_cleanup_storage(lua_State *L, lcurl_easy_t *p){ +static void lcurl_easy_cleanup_storage(lua_State *L, lcurl_easy_t *p){ int i; if(p->storage != LUA_NOREF){ diff --git a/src/lcerror.h b/src/lcerror.h index da4e1c5..d668a58 100644 --- a/src/lcerror.h +++ b/src/lcerror.h @@ -1,34 +1,34 @@ -/****************************************************************************** -* Author: Alexey Melnichuk -* -* Copyright (C) 2014-2018 Alexey Melnichuk -* -* Licensed according to the included 'LICENSE' document -* -* This file is part of Lua-cURL library. -******************************************************************************/ - -#ifndef _LCERROR_H_ -#define _LCERROR_H_ - -#include "lcurl.h" - -#define LCURL_ERROR_CURL 1 -#define LCURL_ERROR_EASY 1 -#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 - -int lcurl_fail(lua_State *L, int error_type, int code); - -int lcurl_fail_ex(lua_State *L, int mode, int error_type, int code); - -int lcurl_error_new(lua_State *L); - -void lcurl_error_initlib(lua_State *L, int nup); - -#endif +/****************************************************************************** +* Author: Alexey Melnichuk +* +* Copyright (C) 2014-2018 Alexey Melnichuk +* +* Licensed according to the included 'LICENSE' document +* +* This file is part of Lua-cURL library. +******************************************************************************/ + +#ifndef _LCERROR_H_ +#define _LCERROR_H_ + +#include "lcurl.h" + +#define LCURL_ERROR_CURL 1 +#define LCURL_ERROR_EASY 1 +#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 + +int lcurl_fail(lua_State *L, int error_type, int code); + +int lcurl_fail_ex(lua_State *L, int mode, int error_type, int code); + +int lcurl_error_new(lua_State *L); + +void lcurl_error_initlib(lua_State *L, int nup); + +#endif diff --git a/src/lcflags.h b/src/lcflags.h index 0fbeff2..351e9f6 100644 --- a/src/lcflags.h +++ b/src/lcflags.h @@ -1,283 +1,283 @@ -/* Bitmasks for CURLOPT_HTTPAUTH and CURLOPT_PROXYAUTH options */ -FLG_ENTRY(AUTH_NONE ) -FLG_ENTRY(AUTH_BASIC ) -FLG_ENTRY(AUTH_DIGEST ) -FLG_ENTRY(AUTH_GSSNEGOTIATE ) -#if LCURL_CURL_VER_GE(7,38,0) -FLG_ENTRY(AUTH_NEGOTIATE ) -#endif -FLG_ENTRY(AUTH_NTLM ) -#if LCURL_CURL_VER_GE(7,19,3) -FLG_ENTRY(AUTH_DIGEST_IE ) -#endif -#if LCURL_CURL_VER_GE(7,19,6) -FLG_ENTRY(KHSTAT_FINE_ADD_TO_FILE ) -FLG_ENTRY(KHSTAT_FINE ) -FLG_ENTRY(KHSTAT_REJECT ) -FLG_ENTRY(KHSTAT_DEFER ) -FLG_ENTRY(KHMATCH_OK ) -FLG_ENTRY(KHMATCH_MISMATCH ) -FLG_ENTRY(KHMATCH_MISSING ) +/* Bitmasks for CURLOPT_HTTPAUTH and CURLOPT_PROXYAUTH options */ +FLG_ENTRY(AUTH_NONE ) +FLG_ENTRY(AUTH_BASIC ) +FLG_ENTRY(AUTH_DIGEST ) +FLG_ENTRY(AUTH_GSSNEGOTIATE ) +#if LCURL_CURL_VER_GE(7,38,0) +FLG_ENTRY(AUTH_NEGOTIATE ) +#endif +FLG_ENTRY(AUTH_NTLM ) +#if LCURL_CURL_VER_GE(7,19,3) +FLG_ENTRY(AUTH_DIGEST_IE ) +#endif +#if LCURL_CURL_VER_GE(7,19,6) +FLG_ENTRY(KHSTAT_FINE_ADD_TO_FILE ) +FLG_ENTRY(KHSTAT_FINE ) +FLG_ENTRY(KHSTAT_REJECT ) +FLG_ENTRY(KHSTAT_DEFER ) +FLG_ENTRY(KHMATCH_OK ) +FLG_ENTRY(KHMATCH_MISMATCH ) +FLG_ENTRY(KHMATCH_MISSING ) FLG_ENTRY(KHTYPE_RSA1 ) FLG_ENTRY(KHTYPE_RSA ) FLG_ENTRY(KHTYPE_DSS ) -#endif -#if LCURL_CURL_VER_GE(7,58,0) +#endif +#if LCURL_CURL_VER_GE(7,58,0) FLG_ENTRY(KHTYPE_ECDSA ) -FLG_ENTRY(KHTYPE_ED25519 ) -#endif -#if LCURL_CURL_VER_GE(7,73,0) -FLG_ENTRY(KHSTAT_FINE_REPLACE ) -#endif - -#if LCURL_CURL_VER_GE(7,22,0) -FLG_ENTRY(AUTH_NTLM_WB ) -#endif -#if LCURL_CURL_VER_GE(7,21,3) -FLG_ENTRY(AUTH_ONLY ) -#endif -FLG_ENTRY(AUTH_ANY ) -FLG_ENTRY(AUTH_ANYSAFE ) -#if LCURL_CURL_VER_GE(7,55,0) -FLG_ENTRY(AUTH_GSSAPI ) -#endif -#if LCURL_CURL_VER_GE(7,61,0) -FLG_ENTRY(AUTH_BEARER ) -#endif - -#ifdef CURLSSH_AUTH_ANY -FLG_ENTRY(SSH_AUTH_ANY ) -#endif -#ifdef CURLSSH_AUTH_NONE -FLG_ENTRY(SSH_AUTH_NONE ) -#endif -#ifdef CURLSSH_AUTH_PUBLICKEY -FLG_ENTRY(SSH_AUTH_PUBLICKEY ) -#endif -#ifdef CURLSSH_AUTH_PASSWORD -FLG_ENTRY(SSH_AUTH_PASSWORD ) -#endif -#ifdef CURLSSH_AUTH_HOST -FLG_ENTRY(SSH_AUTH_HOST ) -#endif -#ifdef CURLSSH_AUTH_GSSAPI -FLG_ENTRY(SSH_AUTH_GSSAPI ) -#endif -#ifdef CURLSSH_AUTH_KEYBOARD -FLG_ENTRY(SSH_AUTH_KEYBOARD ) -#endif -#ifdef CURLSSH_AUTH_AGENT -FLG_ENTRY(SSH_AUTH_AGENT ) -#endif -#ifdef CURLSSH_AUTH_DEFAULT -FLG_ENTRY(SSH_AUTH_DEFAULT ) -#endif - -#ifdef CURLGSSAPI_DELEGATION_NONE -FLG_ENTRY(GSSAPI_DELEGATION_NONE ) -#endif -#ifdef CURLGSSAPI_DELEGATION_POLICY_FLAG -FLG_ENTRY(GSSAPI_DELEGATION_POLICY_FLAG ) -#endif -#ifdef CURLGSSAPI_DELEGATION_FLAG -FLG_ENTRY(GSSAPI_DELEGATION_FLAG ) -#endif - -/* Bitmasks for CURLOPT_HTTPAUTH and CURLOPT_PROXYAUTH options */ -FLG_ENTRY(USESSL_NONE ) -FLG_ENTRY(USESSL_TRY ) -FLG_ENTRY(USESSL_CONTROL ) -FLG_ENTRY(USESSL_ALL ) - -/* Definition of bits for the CURLOPT_SSL_OPTIONS argument: */ -#ifdef CURLSSLOPT_ALLOW_BEAST -FLG_ENTRY(SSLOPT_ALLOW_BEAST ) -#endif -#ifdef CURLSSLOPT_NO_REVOKE -FLG_ENTRY(SSLOPT_NO_REVOKE ) -#endif -#ifdef CURLSSLOPT_NO_PARTIALCHAIN -FLG_ENTRY(SSLOPT_NO_PARTIALCHAIN ) -#endif -#ifdef CURLSSLOPT_REVOKE_BEST_EFFORT -FLG_ENTRY(SSLOPT_REVOKE_BEST_EFFORT ) -#endif -#ifdef CURLSSLOPT_NATIVE_CA -FLG_ENTRY(SSLOPT_NATIVE_CA ) -#endif - -/* parameter for the CURLOPT_FTP_SSL_CCC option */ -FLG_ENTRY(FTPSSL_CCC_NONE ) -FLG_ENTRY(FTPSSL_CCC_PASSIVE ) -FLG_ENTRY(FTPSSL_CCC_ACTIVE ) - -/* parameter for the CURLOPT_FTPSSLAUTH option */ -FLG_ENTRY(FTPAUTH_DEFAULT ) -FLG_ENTRY(FTPAUTH_SSL ) -FLG_ENTRY(FTPAUTH_TLS ) - -/* parameter for the CURLOPT_FTP_CREATE_MISSING_DIRS option */ -FLG_ENTRY(FTP_CREATE_DIR_NONE ) -FLG_ENTRY(FTP_CREATE_DIR ) -FLG_ENTRY(FTP_CREATE_DIR_RETRY ) -FLG_ENTRY(FTP_CREATE_DIR_LAST ) - -/* parameter for the CURLOPT_FTP_FILEMETHOD option */ -FLG_ENTRY(FTPMETHOD_DEFAULT ) -FLG_ENTRY(FTPMETHOD_MULTICWD ) -FLG_ENTRY(FTPMETHOD_NOCWD ) -FLG_ENTRY(FTPMETHOD_SINGLECWD ) - -/* bitmask defines for CURLOPT_HEADEROPT */ -#if LCURL_CURL_VER_GE(7,37,0) -FLG_ENTRY(HEADER_UNIFIED ) -FLG_ENTRY(HEADER_SEPARATE ) -#endif - -/* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */ -FLG_ENTRY(PROTO_HTTP ) -FLG_ENTRY(PROTO_HTTPS ) -FLG_ENTRY(PROTO_FTP ) -FLG_ENTRY(PROTO_FTPS ) -FLG_ENTRY(PROTO_SCP ) -FLG_ENTRY(PROTO_SFTP ) -FLG_ENTRY(PROTO_TELNET ) -FLG_ENTRY(PROTO_LDAP ) -FLG_ENTRY(PROTO_LDAPS ) -FLG_ENTRY(PROTO_DICT ) -FLG_ENTRY(PROTO_FILE ) -FLG_ENTRY(PROTO_TFTP ) -#ifdef CURLPROTO_IMAP -FLG_ENTRY(PROTO_IMAP ) -#endif -#ifdef CURLPROTO_IMAPS -FLG_ENTRY(PROTO_IMAPS ) -#endif -#ifdef CURLPROTO_POP3 -FLG_ENTRY(PROTO_POP3 ) -#endif -#ifdef CURLPROTO_POP3S -FLG_ENTRY(PROTO_POP3S ) -#endif -#ifdef CURLPROTO_SMTP -FLG_ENTRY(PROTO_SMTP ) -#endif -#ifdef CURLPROTO_SMTPS -FLG_ENTRY(PROTO_SMTPS ) -#endif -#ifdef CURLPROTO_RTSP -FLG_ENTRY(PROTO_RTSP ) -#endif -#ifdef CURLPROTO_RTMP -FLG_ENTRY(PROTO_RTMP ) -#endif -#ifdef CURLPROTO_RTMPT -FLG_ENTRY(PROTO_RTMPT ) -#endif -#ifdef CURLPROTO_RTMPE -FLG_ENTRY(PROTO_RTMPE ) -#endif -#ifdef CURLPROTO_RTMPTE -FLG_ENTRY(PROTO_RTMPTE ) -#endif -#ifdef CURLPROTO_RTMPS -FLG_ENTRY(PROTO_RTMPS ) -#endif -#ifdef CURLPROTO_RTMPTS -FLG_ENTRY(PROTO_RTMPTS ) -#endif -#ifdef CURLPROTO_GOPHER -FLG_ENTRY(PROTO_GOPHER ) -#endif -#ifdef CURLPROTO_SMB -FLG_ENTRY(PROTO_SMB ) -#endif -#ifdef CURLPROTO_SMBS -FLG_ENTRY(PROTO_SMBS ) -#endif -#ifdef CURLPROTO_MQTT -FLG_ENTRY(PROTO_MQTT ) -#endif -FLG_ENTRY(PROTO_ALL ) - -FLG_ENTRY(PROXY_HTTP ) /* added in 7.10.0 */ -FLG_ENTRY(PROXY_HTTP_1_0 ) /* added in 7.19.4 */ -FLG_ENTRY(PROXY_SOCKS4 ) /* added in 7.15.2 */ -FLG_ENTRY(PROXY_SOCKS5 ) /* added in 7.10.0 */ -FLG_ENTRY(PROXY_SOCKS4A ) /* added in 7.18.0 */ -FLG_ENTRY(PROXY_SOCKS5_HOSTNAME ) /* added in 7.18.0 */ -#if LCURL_CURL_VER_GE(7,52,0) -FLG_ENTRY(PROXY_HTTPS ) -#endif - -FLG_ENTRY(PAUSE_ALL ) /* added in 7.18.0 */ -FLG_ENTRY(PAUSE_CONT ) /* added in 7.18.0 */ -FLG_ENTRY(PAUSE_RECV ) /* added in 7.18.0 */ -FLG_ENTRY(PAUSE_RECV_CONT ) /* added in 7.18.0 */ -FLG_ENTRY(PAUSE_SEND ) /* added in 7.18.0 */ -FLG_ENTRY(PAUSE_SEND_CONT ) /* added in 7.18.0 */ - -#if LCURL_CURL_VER_GE(7,64,1) -FLG_ENTRY(ALTSVC_H1) -FLG_ENTRY(ALTSVC_H2) -FLG_ENTRY(ALTSVC_H3) -FLG_ENTRY(ALTSVC_READONLYFILE) -#endif - -#if LCURL_CURL_VER_GE(7,73,0) -FLG_ENTRY(PX_OK) -FLG_ENTRY(PX_BAD_ADDRESS_TYPE) -FLG_ENTRY(PX_BAD_VERSION) -FLG_ENTRY(PX_CLOSED) -FLG_ENTRY(PX_GSSAPI) -FLG_ENTRY(PX_GSSAPI_PERMSG) -FLG_ENTRY(PX_GSSAPI_PROTECTION) -FLG_ENTRY(PX_IDENTD) -FLG_ENTRY(PX_IDENTD_DIFFER) -FLG_ENTRY(PX_LONG_HOSTNAME) -FLG_ENTRY(PX_LONG_PASSWD) -FLG_ENTRY(PX_LONG_USER) -FLG_ENTRY(PX_NO_AUTH) -FLG_ENTRY(PX_RECV_ADDRESS) -FLG_ENTRY(PX_RECV_AUTH) -FLG_ENTRY(PX_RECV_CONNECT) -FLG_ENTRY(PX_RECV_REQACK) -FLG_ENTRY(PX_REPLY_ADDRESS_TYPE_NOT_SUPPORTED) -FLG_ENTRY(PX_REPLY_COMMAND_NOT_SUPPORTED) -FLG_ENTRY(PX_REPLY_CONNECTION_REFUSED) -FLG_ENTRY(PX_REPLY_GENERAL_SERVER_FAILURE) -FLG_ENTRY(PX_REPLY_HOST_UNREACHABLE) -FLG_ENTRY(PX_REPLY_NETWORK_UNREACHABLE) -FLG_ENTRY(PX_REPLY_NOT_ALLOWED) -FLG_ENTRY(PX_REPLY_TTL_EXPIRED) -FLG_ENTRY(PX_REPLY_UNASSIGNED) -FLG_ENTRY(PX_REQUEST_FAILED) -FLG_ENTRY(PX_RESOLVE_HOST) -FLG_ENTRY(PX_SEND_AUTH) -FLG_ENTRY(PX_SEND_CONNECT) -FLG_ENTRY(PX_SEND_REQUEST) -FLG_ENTRY(PX_UNKNOWN_FAIL) -FLG_ENTRY(PX_UNKNOWN_MODE) -FLG_ENTRY(PX_USER_REJECTED) -#endif - -#if LCURL_CURL_VER_GE(7,73,0) -FLG_ENTRY(OT_LONG) -FLG_ENTRY(OT_VALUES) -FLG_ENTRY(OT_OFF_T) -FLG_ENTRY(OT_OBJECT) -FLG_ENTRY(OT_STRING) -FLG_ENTRY(OT_SLIST) -FLG_ENTRY(OT_CBPTR) -FLG_ENTRY(OT_BLOB) -FLG_ENTRY(OT_FUNCTION) -FLG_ENTRY(OT_FLAG_ALIAS) -#endif - -#if LCURL_CURL_VER_GE(7,74,0) && LCURL_USE_HSTS -FLG_ENTRY(HSTS_ENABLE) -FLG_ENTRY(HSTS_READONLYFILE) -FLG_ENTRY(STS_OK) -FLG_ENTRY(STS_DONE) -FLG_ENTRY(STS_FAIL) -#endif +FLG_ENTRY(KHTYPE_ED25519 ) +#endif +#if LCURL_CURL_VER_GE(7,73,0) +FLG_ENTRY(KHSTAT_FINE_REPLACE ) +#endif + +#if LCURL_CURL_VER_GE(7,22,0) +FLG_ENTRY(AUTH_NTLM_WB ) +#endif +#if LCURL_CURL_VER_GE(7,21,3) +FLG_ENTRY(AUTH_ONLY ) +#endif +FLG_ENTRY(AUTH_ANY ) +FLG_ENTRY(AUTH_ANYSAFE ) +#if LCURL_CURL_VER_GE(7,55,0) +FLG_ENTRY(AUTH_GSSAPI ) +#endif +#if LCURL_CURL_VER_GE(7,61,0) +FLG_ENTRY(AUTH_BEARER ) +#endif + +#ifdef CURLSSH_AUTH_ANY +FLG_ENTRY(SSH_AUTH_ANY ) +#endif +#ifdef CURLSSH_AUTH_NONE +FLG_ENTRY(SSH_AUTH_NONE ) +#endif +#ifdef CURLSSH_AUTH_PUBLICKEY +FLG_ENTRY(SSH_AUTH_PUBLICKEY ) +#endif +#ifdef CURLSSH_AUTH_PASSWORD +FLG_ENTRY(SSH_AUTH_PASSWORD ) +#endif +#ifdef CURLSSH_AUTH_HOST +FLG_ENTRY(SSH_AUTH_HOST ) +#endif +#ifdef CURLSSH_AUTH_GSSAPI +FLG_ENTRY(SSH_AUTH_GSSAPI ) +#endif +#ifdef CURLSSH_AUTH_KEYBOARD +FLG_ENTRY(SSH_AUTH_KEYBOARD ) +#endif +#ifdef CURLSSH_AUTH_AGENT +FLG_ENTRY(SSH_AUTH_AGENT ) +#endif +#ifdef CURLSSH_AUTH_DEFAULT +FLG_ENTRY(SSH_AUTH_DEFAULT ) +#endif + +#ifdef CURLGSSAPI_DELEGATION_NONE +FLG_ENTRY(GSSAPI_DELEGATION_NONE ) +#endif +#ifdef CURLGSSAPI_DELEGATION_POLICY_FLAG +FLG_ENTRY(GSSAPI_DELEGATION_POLICY_FLAG ) +#endif +#ifdef CURLGSSAPI_DELEGATION_FLAG +FLG_ENTRY(GSSAPI_DELEGATION_FLAG ) +#endif + +/* Bitmasks for CURLOPT_HTTPAUTH and CURLOPT_PROXYAUTH options */ +FLG_ENTRY(USESSL_NONE ) +FLG_ENTRY(USESSL_TRY ) +FLG_ENTRY(USESSL_CONTROL ) +FLG_ENTRY(USESSL_ALL ) + +/* Definition of bits for the CURLOPT_SSL_OPTIONS argument: */ +#ifdef CURLSSLOPT_ALLOW_BEAST +FLG_ENTRY(SSLOPT_ALLOW_BEAST ) +#endif +#ifdef CURLSSLOPT_NO_REVOKE +FLG_ENTRY(SSLOPT_NO_REVOKE ) +#endif +#ifdef CURLSSLOPT_NO_PARTIALCHAIN +FLG_ENTRY(SSLOPT_NO_PARTIALCHAIN ) +#endif +#ifdef CURLSSLOPT_REVOKE_BEST_EFFORT +FLG_ENTRY(SSLOPT_REVOKE_BEST_EFFORT ) +#endif +#ifdef CURLSSLOPT_NATIVE_CA +FLG_ENTRY(SSLOPT_NATIVE_CA ) +#endif + +/* parameter for the CURLOPT_FTP_SSL_CCC option */ +FLG_ENTRY(FTPSSL_CCC_NONE ) +FLG_ENTRY(FTPSSL_CCC_PASSIVE ) +FLG_ENTRY(FTPSSL_CCC_ACTIVE ) + +/* parameter for the CURLOPT_FTPSSLAUTH option */ +FLG_ENTRY(FTPAUTH_DEFAULT ) +FLG_ENTRY(FTPAUTH_SSL ) +FLG_ENTRY(FTPAUTH_TLS ) + +/* parameter for the CURLOPT_FTP_CREATE_MISSING_DIRS option */ +FLG_ENTRY(FTP_CREATE_DIR_NONE ) +FLG_ENTRY(FTP_CREATE_DIR ) +FLG_ENTRY(FTP_CREATE_DIR_RETRY ) +FLG_ENTRY(FTP_CREATE_DIR_LAST ) + +/* parameter for the CURLOPT_FTP_FILEMETHOD option */ +FLG_ENTRY(FTPMETHOD_DEFAULT ) +FLG_ENTRY(FTPMETHOD_MULTICWD ) +FLG_ENTRY(FTPMETHOD_NOCWD ) +FLG_ENTRY(FTPMETHOD_SINGLECWD ) + +/* bitmask defines for CURLOPT_HEADEROPT */ +#if LCURL_CURL_VER_GE(7,37,0) +FLG_ENTRY(HEADER_UNIFIED ) +FLG_ENTRY(HEADER_SEPARATE ) +#endif + +/* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */ +FLG_ENTRY(PROTO_HTTP ) +FLG_ENTRY(PROTO_HTTPS ) +FLG_ENTRY(PROTO_FTP ) +FLG_ENTRY(PROTO_FTPS ) +FLG_ENTRY(PROTO_SCP ) +FLG_ENTRY(PROTO_SFTP ) +FLG_ENTRY(PROTO_TELNET ) +FLG_ENTRY(PROTO_LDAP ) +FLG_ENTRY(PROTO_LDAPS ) +FLG_ENTRY(PROTO_DICT ) +FLG_ENTRY(PROTO_FILE ) +FLG_ENTRY(PROTO_TFTP ) +#ifdef CURLPROTO_IMAP +FLG_ENTRY(PROTO_IMAP ) +#endif +#ifdef CURLPROTO_IMAPS +FLG_ENTRY(PROTO_IMAPS ) +#endif +#ifdef CURLPROTO_POP3 +FLG_ENTRY(PROTO_POP3 ) +#endif +#ifdef CURLPROTO_POP3S +FLG_ENTRY(PROTO_POP3S ) +#endif +#ifdef CURLPROTO_SMTP +FLG_ENTRY(PROTO_SMTP ) +#endif +#ifdef CURLPROTO_SMTPS +FLG_ENTRY(PROTO_SMTPS ) +#endif +#ifdef CURLPROTO_RTSP +FLG_ENTRY(PROTO_RTSP ) +#endif +#ifdef CURLPROTO_RTMP +FLG_ENTRY(PROTO_RTMP ) +#endif +#ifdef CURLPROTO_RTMPT +FLG_ENTRY(PROTO_RTMPT ) +#endif +#ifdef CURLPROTO_RTMPE +FLG_ENTRY(PROTO_RTMPE ) +#endif +#ifdef CURLPROTO_RTMPTE +FLG_ENTRY(PROTO_RTMPTE ) +#endif +#ifdef CURLPROTO_RTMPS +FLG_ENTRY(PROTO_RTMPS ) +#endif +#ifdef CURLPROTO_RTMPTS +FLG_ENTRY(PROTO_RTMPTS ) +#endif +#ifdef CURLPROTO_GOPHER +FLG_ENTRY(PROTO_GOPHER ) +#endif +#ifdef CURLPROTO_SMB +FLG_ENTRY(PROTO_SMB ) +#endif +#ifdef CURLPROTO_SMBS +FLG_ENTRY(PROTO_SMBS ) +#endif +#ifdef CURLPROTO_MQTT +FLG_ENTRY(PROTO_MQTT ) +#endif +FLG_ENTRY(PROTO_ALL ) + +FLG_ENTRY(PROXY_HTTP ) /* added in 7.10.0 */ +FLG_ENTRY(PROXY_HTTP_1_0 ) /* added in 7.19.4 */ +FLG_ENTRY(PROXY_SOCKS4 ) /* added in 7.15.2 */ +FLG_ENTRY(PROXY_SOCKS5 ) /* added in 7.10.0 */ +FLG_ENTRY(PROXY_SOCKS4A ) /* added in 7.18.0 */ +FLG_ENTRY(PROXY_SOCKS5_HOSTNAME ) /* added in 7.18.0 */ +#if LCURL_CURL_VER_GE(7,52,0) +FLG_ENTRY(PROXY_HTTPS ) +#endif + +FLG_ENTRY(PAUSE_ALL ) /* added in 7.18.0 */ +FLG_ENTRY(PAUSE_CONT ) /* added in 7.18.0 */ +FLG_ENTRY(PAUSE_RECV ) /* added in 7.18.0 */ +FLG_ENTRY(PAUSE_RECV_CONT ) /* added in 7.18.0 */ +FLG_ENTRY(PAUSE_SEND ) /* added in 7.18.0 */ +FLG_ENTRY(PAUSE_SEND_CONT ) /* added in 7.18.0 */ + +#if LCURL_CURL_VER_GE(7,64,1) +FLG_ENTRY(ALTSVC_H1) +FLG_ENTRY(ALTSVC_H2) +FLG_ENTRY(ALTSVC_H3) +FLG_ENTRY(ALTSVC_READONLYFILE) +#endif + +#if LCURL_CURL_VER_GE(7,73,0) +FLG_ENTRY(PX_OK) +FLG_ENTRY(PX_BAD_ADDRESS_TYPE) +FLG_ENTRY(PX_BAD_VERSION) +FLG_ENTRY(PX_CLOSED) +FLG_ENTRY(PX_GSSAPI) +FLG_ENTRY(PX_GSSAPI_PERMSG) +FLG_ENTRY(PX_GSSAPI_PROTECTION) +FLG_ENTRY(PX_IDENTD) +FLG_ENTRY(PX_IDENTD_DIFFER) +FLG_ENTRY(PX_LONG_HOSTNAME) +FLG_ENTRY(PX_LONG_PASSWD) +FLG_ENTRY(PX_LONG_USER) +FLG_ENTRY(PX_NO_AUTH) +FLG_ENTRY(PX_RECV_ADDRESS) +FLG_ENTRY(PX_RECV_AUTH) +FLG_ENTRY(PX_RECV_CONNECT) +FLG_ENTRY(PX_RECV_REQACK) +FLG_ENTRY(PX_REPLY_ADDRESS_TYPE_NOT_SUPPORTED) +FLG_ENTRY(PX_REPLY_COMMAND_NOT_SUPPORTED) +FLG_ENTRY(PX_REPLY_CONNECTION_REFUSED) +FLG_ENTRY(PX_REPLY_GENERAL_SERVER_FAILURE) +FLG_ENTRY(PX_REPLY_HOST_UNREACHABLE) +FLG_ENTRY(PX_REPLY_NETWORK_UNREACHABLE) +FLG_ENTRY(PX_REPLY_NOT_ALLOWED) +FLG_ENTRY(PX_REPLY_TTL_EXPIRED) +FLG_ENTRY(PX_REPLY_UNASSIGNED) +FLG_ENTRY(PX_REQUEST_FAILED) +FLG_ENTRY(PX_RESOLVE_HOST) +FLG_ENTRY(PX_SEND_AUTH) +FLG_ENTRY(PX_SEND_CONNECT) +FLG_ENTRY(PX_SEND_REQUEST) +FLG_ENTRY(PX_UNKNOWN_FAIL) +FLG_ENTRY(PX_UNKNOWN_MODE) +FLG_ENTRY(PX_USER_REJECTED) +#endif + +#if LCURL_CURL_VER_GE(7,73,0) +FLG_ENTRY(OT_LONG) +FLG_ENTRY(OT_VALUES) +FLG_ENTRY(OT_OFF_T) +FLG_ENTRY(OT_OBJECT) +FLG_ENTRY(OT_STRING) +FLG_ENTRY(OT_SLIST) +FLG_ENTRY(OT_CBPTR) +FLG_ENTRY(OT_BLOB) +FLG_ENTRY(OT_FUNCTION) +FLG_ENTRY(OT_FLAG_ALIAS) +#endif + +#if LCURL_CURL_VER_GE(7,74,0) && LCURL_USE_HSTS +FLG_ENTRY(HSTS_ENABLE) +FLG_ENTRY(HSTS_READONLYFILE) +FLG_ENTRY(STS_OK) +FLG_ENTRY(STS_DONE) +FLG_ENTRY(STS_FAIL) +#endif diff --git a/src/lcmime.c b/src/lcmime.c index 90fd6b4..4a8d15b 100644 --- a/src/lcmime.c +++ b/src/lcmime.c @@ -183,7 +183,7 @@ static int lcurl_mime_part_assing_table(lua_State *L, int part, int t){ assert(top == lua_gettop(L)); } else{ - for(i=0;method = lcurl_mime_part_fields[i]; ++i){ + for(i=0; (method = lcurl_mime_part_fields[i]) != NULL; ++i){ lua_getfield(L, t, method); if(!lua_isnil(L, -1)){ int ret = lcurl_mime_part_assign(L, part, method); diff --git a/test/test_curl.lua b/test/test_curl.lua index ce6a44a..60ff675 100644 --- a/test/test_curl.lua +++ b/test/test_curl.lua @@ -1,451 +1,451 @@ -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 json = require "dkjson" -local fname = "./test.download" - -local utils = require "utils" - -local weak_ptr, gc_collect, is_curl_ge, is_curl_eq, read_file, stream, Stream, dump_request = - utils.import('weak_ptr', 'gc_collect', 'is_curl_ge', 'is_curl_eq', 'read_file', 'stream', 'Stream', 'dump_request') - --- Bug. libcurl 7.56.0 does not add `Content-Type: text/plain` -local text_plain = is_curl_eq(7,56,0) and 'test/plain' or 'text/plain' - -local GET_URL = "http://127.0.0.1:7090/get" - -local ENABLE = true - -local _ENV = TEST_CASE'version' if ENABLE then - -function test() - assert_match("^%d+%.%d+%.%d+%-?", curl._VERSION) - assert_equal("Lua-cURL", curl._NAME ) -end - -end - -local _ENV = TEST_CASE'easy' if ENABLE then - -local e1, e2 -function teardown() - if e1 then e1:close() end - if e2 then e2:close() end - e1, e2 = nil -end - -if curl.OPT_STREAM_DEPENDS then - -function test_easy_setopt_stream_depends_1() - e1 = assert(scurl.easy()) - e2 = assert(scurl.easy()) - assert_pass(function() - e1:setopt_stream_depends(e2) - end) -end - -function test_easy_setopt_stream_depends_2() - e1 = assert(scurl.easy()) - e2 = assert(scurl.easy()) - assert_pass(function() - e1:setopt(curl.OPT_STREAM_DEPENDS, e2) - end) -end - -function test_easy_setopt_stream_depends_3() - e1 = assert(scurl.easy()) - e2 = assert(scurl.easy()) - assert_pass(function() - e1:setopt{[curl.OPT_STREAM_DEPENDS] = e2} - end) -end - -function test_easy_setopt_stream_depends_4() - e1 = assert(scurl.easy()) - e2 = assert(scurl.easy()) - assert_pass(function() - e1:setopt{stream_depends = e2} - end) -end - -function test_easy_setopt_stream_depends_e_1() - e1 = assert(scurl.easy()) - e2 = assert(scurl.easy()) - assert_pass(function() - e1:setopt_stream_depends_e(e2) - end) -end - -function test_easy_setopt_stream_depends_e_2() - e1 = assert(scurl.easy()) - e2 = assert(scurl.easy()) - assert_pass(function() - e1:setopt(curl.OPT_STREAM_DEPENDS_E, e2) - end) -end - -function test_easy_setopt_stream_depends_e_3() - e1 = assert(scurl.easy()) - e2 = assert(scurl.easy()) - assert_pass(function() - e1:setopt{[curl.OPT_STREAM_DEPENDS_E] = e2} - end) -end - -function test_easy_setopt_stream_depends_e_4() - e1 = assert(scurl.easy()) - e2 = assert(scurl.easy()) - assert_pass(function() - e1:setopt{stream_depends_e = e2} - end) -end - -end - -function test_easy_setopt_share() - e1 = assert(scurl.easy()) - e2 = assert(scurl.share()) - assert_pass(function() - e1:setopt_share(e2) - end) -end - -end - -local _ENV = TEST_CASE'multi_iterator' if ENABLE then - -local url = GET_URL - -local c, t, m - -local function json_data() - return json.decode(table.concat(t)) -end - -function setup() - t = {} - m = assert(scurl.multi()) -end - -function teardown() - if m then m:close() end - if c then c:close() end - m, c, t = nil -end - -function test_add_handle() - local base_url = url .. '?key=' - local urls = { - base_url .. "1", - base_url .. "2", - "###" .. base_url .. "3", - base_url .. "4", - base_url .. "5", - } - - local i = 0 - local function next_easy() - i = i + 1 - local url = urls[i] - if url then - c = assert(scurl.easy{url = url}) - t = {} - return c - end - end - - assert_equal(m, m:add_handle(next_easy())) - - for data, type, easy in m:iperform() do - - if type == "done" or type == "error" then - assert_equal(urls[i], easy:getinfo_effective_url()) - assert_equal(easy, c) - easy:close() - c = nil - - if i == 3 then - if is_curl_ge(7, 62,0) then - assert_equal(curl.error(curl.ERROR_EASY, curl.E_URL_MALFORMAT), data) - else - assert_equal(curl.error(curl.ERROR_EASY, curl.E_UNSUPPORTED_PROTOCOL), data) - end - else - local data = json_data() - assert_table(data.args) - assert_equal(tostring(i), data.args.key) - end - - easy = next_easy() - if easy then m:add_handle(easy) end - end - - if type == "data" then table.insert(t, data) end - - end - - assert_equal(#urls + 1, i) - assert_nil(c) -end - -function test_info_read() - - local url = GET_URL .. '?key=1' - - c = assert(curl.easy{url=url, writefunction=function() end}) - assert_equal(m, m:add_handle(c)) - - while m:perform() > 0 do m:wait() end - - local h, ok, err = m:info_read() - assert_equal(c, h) - - local h, ok, err = m:info_read() - assert_equal(0, h) -end - -end - -local _ENV = TEST_CASE'multi memory leak' if ENABLE then - -local m - -function teardown() - if m then m:close() end - m = nil -end - -function test_basic() - local ptr do - local multi = assert(scurl.multi()) - ptr = weak_ptr(multi) - end - gc_collect() - - assert_nil(ptr.value) -end - -function test_socket_action() - local ptr do - local multi = assert(scurl.multi()) - multi:setopt_socketfunction(function() end) - ptr = weak_ptr(multi) - end - gc_collect() - - assert_nil(ptr.value) -end - -end - -local _ENV = TEST_CASE'form' if ENABLE then - -local post - -function teardown() - if post then post:free() end - post = nil -end - -function test_content_01() - post = assert(scurl.form{name01 = 'value01'}) - local data = assert_string(post:get()) - assert_match("\r\n\r\nvalue01\r\n", data) - assert_match('name="name01"', data) -end - -function test_content_02() - post = assert(scurl.form{name02 = {'value02', type = text_plain}}) - local data = assert_string(post:get()) - assert_match("\r\n\r\nvalue02\r\n", data) - assert_match('name="name02"', data) - assert_match('Content%-Type: ' .. text_plain .. '\r\n', data) -end - -function test_content_03() - post = assert(scurl.form{name03 = {content = 'value03', headers = {"Content-Encoding: gzip"}}}) - local data = assert_string(post:get()) - assert_match("\r\n\r\nvalue03\r\n", data) - assert_match('name="name03"', data) - assert_match('Content%-Encoding: gzip\r\n', data) -end - -function test_content_04() - post = assert(scurl.form{name04 = {'value04', type = text_plain, headers = {"Content-Encoding: gzip"}}}) - local data = assert_string(post:get()) - assert_match("\r\n\r\nvalue04\r\n", data) - assert_match('name="name04"', data) - assert_match('Content%-Encoding: gzip\r\n', data) - assert_match('Content%-Type: ' .. text_plain .. '\r\n', data) -end - -function test_buffer_01() - post = assert(scurl.form{name01 = { - name = 'file01', - data = 'value01', - }}) - - local data = assert_string(post:get()) - assert_match("\r\n\r\nvalue01\r\n", data) - assert_match('name="name01"', data) - assert_match('filename="file01"', data) - assert_match('Content%-Type: application/octet%-stream\r\n', data) -end - -function test_buffer_02() - post = assert(scurl.form{name02 = { - name = 'file02', - data = 'value02', - type = text_plain, - }}) - - local data = assert_string(post:get()) - assert_match("\r\n\r\nvalue02\r\n", data) - assert_match('name="name02"', data) - assert_match('filename="file02"', data) - assert_match('Content%-Type: ' .. text_plain .. '\r\n', data) - assert_not_match('Content%-Type: application/octet%-stream\r\n', data) -end - -function test_buffer_03() - post = assert(scurl.form{name03 = { - name = 'file03', - data = 'value03', - headers = {"Content-Encoding: gzip"}, - }}) - local data = assert_string(post:get()) - assert_match("\r\n\r\nvalue03\r\n", data) - assert_match('name="name03"', data) - assert_match('filename="file03"', data) - assert_match('Content%-Type: application/octet%-stream\r\n', data) - assert_match('Content%-Encoding: gzip\r\n', data) -end - -function test_buffer_04() - post = assert(scurl.form{name04 = { - name = 'file04', - data = 'value04', - type = text_plain, - headers = {"Content-Encoding: gzip"}, - }}) - - local data = assert_string(post:get()) - assert_match("\r\n\r\nvalue04\r\n", data) - assert_match('name="name04"', data) - assert_match('filename="file04"', data) - assert_match('Content%-Type: ' .. text_plain .. '\r\n', data) - assert_not_match('Content%-Type: application/octet%-stream\r\n', data) - assert_match('Content%-Encoding: gzip\r\n', data) -end - -function test_stream_01() - post = assert(scurl.form{name01 = { - stream = function() end, - length = 128, - }}) - local data = assert_string(post:get()) - assert_match('name="name01"', data) - assert_not_match('filename', data) -end - -function test_stream_02() - post = assert(scurl.form{name02 = { - name = 'file02', - stream = function() end, - length = 128, - }}) - local data = assert_string(post:get()) - assert_match('name="name02"', data) - assert_match('filename="file02"', data) -end - -function test_stream_03() - post = assert(scurl.form{name03 = { - name = 'file03', - stream = function() end, - length = 128, - type = text_plain, - }}) - - local data = assert_string(post:get()) - assert_match('name="name03"', data) - assert_match('filename="file03"', data) - assert_match('Content%-Type: ' .. text_plain .. '\r\n', data) -end - -function test_stream_04() - post = assert(scurl.form{name04 = { - name = 'file04', - stream = function() end, - length = 128, - type = text_plain, - headers = {"Content-Encoding: gzip"}, - }}) - local data = assert_string(post:get()) - assert_match('name="name04"', data) - assert_match('filename="file04"', data) - assert_match('Content%-Type: ' .. text_plain .. '\r\n', data) - assert_match('Content%-Encoding: gzip\r\n', data) -end - -function test_stream_05() - post = assert(scurl.form{name05 = { - stream = { - length = function() return 128 end; - read = function() end; - } - }}) - local data = assert_string(post:get()) - assert_match('name="name05"', data) - assert_not_match('filename', data) -end - -function test_error() - assert_error(function() post = scurl.form{name = {content = 1}} end) - assert_error(function() post = scurl.form{name = {1}} end) - assert_error(function() post = scurl.form{name = {data = {}}} end) - assert_error(function() post = scurl.form{name = {file = true}} end) - assert_error(function() post = scurl.form{name = {stream = function() end}} end) - assert_error(function() post = scurl.form{name = {stream = {}}} end) - assert_error(function() post = scurl.form{name = {stream = { - read=function()end;length=function()end - }}}end) - assert_error(function() post = scurl.form{name = {stream = { - read=function()end;length=function() return "123" end - }}}end) - assert_error(function() post = scurl.form{name = {stream = { - read=function()end;length=function() return "hello" end - }}}end) -end - -function test_ignore_unknown() - post = assert(scurl.form{ - name01 = {}, - name02 = {name = "helo"}, - }) - local data = assert_string(post:get()) - assert_not_match('name="name01"', data) - assert_not_match('name="name02"', data) -end - -function test_empty() - post = assert(scurl.form{}) -end - -end - -RUN() +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 json = require "dkjson" +local fname = "./test.download" + +local utils = require "utils" + +local weak_ptr, gc_collect, is_curl_ge, is_curl_eq, read_file, stream, Stream, dump_request = + utils.import('weak_ptr', 'gc_collect', 'is_curl_ge', 'is_curl_eq', 'read_file', 'stream', 'Stream', 'dump_request') + +-- Bug. libcurl 7.56.0 does not add `Content-Type: text/plain` +local text_plain = is_curl_eq(7,56,0) and 'test/plain' or 'text/plain' + +local GET_URL = "http://127.0.0.1:7090/get" + +local ENABLE = true + +local _ENV = TEST_CASE'version' if ENABLE then + +function test() + assert_match("^%d+%.%d+%.%d+%-?", curl._VERSION) + assert_equal("Lua-cURL", curl._NAME ) +end + +end + +local _ENV = TEST_CASE'easy' if ENABLE then + +local e1, e2 +function teardown() + if e1 then e1:close() end + if e2 then e2:close() end + e1, e2 = nil +end + +if curl.OPT_STREAM_DEPENDS then + +function test_easy_setopt_stream_depends_1() + e1 = assert(scurl.easy()) + e2 = assert(scurl.easy()) + assert_pass(function() + e1:setopt_stream_depends(e2) + end) +end + +function test_easy_setopt_stream_depends_2() + e1 = assert(scurl.easy()) + e2 = assert(scurl.easy()) + assert_pass(function() + e1:setopt(curl.OPT_STREAM_DEPENDS, e2) + end) +end + +function test_easy_setopt_stream_depends_3() + e1 = assert(scurl.easy()) + e2 = assert(scurl.easy()) + assert_pass(function() + e1:setopt{[curl.OPT_STREAM_DEPENDS] = e2} + end) +end + +function test_easy_setopt_stream_depends_4() + e1 = assert(scurl.easy()) + e2 = assert(scurl.easy()) + assert_pass(function() + e1:setopt{stream_depends = e2} + end) +end + +function test_easy_setopt_stream_depends_e_1() + e1 = assert(scurl.easy()) + e2 = assert(scurl.easy()) + assert_pass(function() + e1:setopt_stream_depends_e(e2) + end) +end + +function test_easy_setopt_stream_depends_e_2() + e1 = assert(scurl.easy()) + e2 = assert(scurl.easy()) + assert_pass(function() + e1:setopt(curl.OPT_STREAM_DEPENDS_E, e2) + end) +end + +function test_easy_setopt_stream_depends_e_3() + e1 = assert(scurl.easy()) + e2 = assert(scurl.easy()) + assert_pass(function() + e1:setopt{[curl.OPT_STREAM_DEPENDS_E] = e2} + end) +end + +function test_easy_setopt_stream_depends_e_4() + e1 = assert(scurl.easy()) + e2 = assert(scurl.easy()) + assert_pass(function() + e1:setopt{stream_depends_e = e2} + end) +end + +end + +function test_easy_setopt_share() + e1 = assert(scurl.easy()) + e2 = assert(scurl.share()) + assert_pass(function() + e1:setopt_share(e2) + end) +end + +end + +local _ENV = TEST_CASE'multi_iterator' if ENABLE then + +local url = GET_URL + +local c, t, m + +local function json_data() + return json.decode(table.concat(t)) +end + +function setup() + t = {} + m = assert(scurl.multi()) +end + +function teardown() + if m then m:close() end + if c then c:close() end + m, c, t = nil +end + +function test_add_handle() + local base_url = url .. '?key=' + local urls = { + base_url .. "1", + base_url .. "2", + "###" .. base_url .. "3", + base_url .. "4", + base_url .. "5", + } + + local i = 0 + local function next_easy() + i = i + 1 + local url = urls[i] + if url then + c = assert(scurl.easy{url = url}) + t = {} + return c + end + end + + assert_equal(m, m:add_handle(next_easy())) + + for data, type, easy in m:iperform() do + + if type == "done" or type == "error" then + assert_equal(urls[i], easy:getinfo_effective_url()) + assert_equal(easy, c) + easy:close() + c = nil + + if i == 3 then + if is_curl_ge(7, 62,0) then + assert_equal(curl.error(curl.ERROR_EASY, curl.E_URL_MALFORMAT), data) + else + assert_equal(curl.error(curl.ERROR_EASY, curl.E_UNSUPPORTED_PROTOCOL), data) + end + else + local data = json_data() + assert_table(data.args) + assert_equal(tostring(i), data.args.key) + end + + easy = next_easy() + if easy then m:add_handle(easy) end + end + + if type == "data" then table.insert(t, data) end + + end + + assert_equal(#urls + 1, i) + assert_nil(c) +end + +function test_info_read() + + local url = GET_URL .. '?key=1' + + c = assert(curl.easy{url=url, writefunction=function() end}) + assert_equal(m, m:add_handle(c)) + + while m:perform() > 0 do m:wait() end + + local h, ok, err = m:info_read() + assert_equal(c, h) + + local h, ok, err = m:info_read() + assert_equal(0, h) +end + +end + +local _ENV = TEST_CASE'multi memory leak' if ENABLE then + +local m + +function teardown() + if m then m:close() end + m = nil +end + +function test_basic() + local ptr do + local multi = assert(scurl.multi()) + ptr = weak_ptr(multi) + end + gc_collect() + + assert_nil(ptr.value) +end + +function test_socket_action() + local ptr do + local multi = assert(scurl.multi()) + multi:setopt_socketfunction(function() end) + ptr = weak_ptr(multi) + end + gc_collect() + + assert_nil(ptr.value) +end + +end + +local _ENV = TEST_CASE'form' if ENABLE then + +local post + +function teardown() + if post then post:free() end + post = nil +end + +function test_content_01() + post = assert(scurl.form{name01 = 'value01'}) + local data = assert_string(post:get()) + assert_match("\r\n\r\nvalue01\r\n", data) + assert_match('name="name01"', data) +end + +function test_content_02() + post = assert(scurl.form{name02 = {'value02', type = text_plain}}) + local data = assert_string(post:get()) + assert_match("\r\n\r\nvalue02\r\n", data) + assert_match('name="name02"', data) + assert_match('Content%-Type: ' .. text_plain .. '\r\n', data) +end + +function test_content_03() + post = assert(scurl.form{name03 = {content = 'value03', headers = {"Content-Encoding: gzip"}}}) + local data = assert_string(post:get()) + assert_match("\r\n\r\nvalue03\r\n", data) + assert_match('name="name03"', data) + assert_match('Content%-Encoding: gzip\r\n', data) +end + +function test_content_04() + post = assert(scurl.form{name04 = {'value04', type = text_plain, headers = {"Content-Encoding: gzip"}}}) + local data = assert_string(post:get()) + assert_match("\r\n\r\nvalue04\r\n", data) + assert_match('name="name04"', data) + assert_match('Content%-Encoding: gzip\r\n', data) + assert_match('Content%-Type: ' .. text_plain .. '\r\n', data) +end + +function test_buffer_01() + post = assert(scurl.form{name01 = { + name = 'file01', + data = 'value01', + }}) + + local data = assert_string(post:get()) + assert_match("\r\n\r\nvalue01\r\n", data) + assert_match('name="name01"', data) + assert_match('filename="file01"', data) + assert_match('Content%-Type: application/octet%-stream\r\n', data) +end + +function test_buffer_02() + post = assert(scurl.form{name02 = { + name = 'file02', + data = 'value02', + type = text_plain, + }}) + + local data = assert_string(post:get()) + assert_match("\r\n\r\nvalue02\r\n", data) + assert_match('name="name02"', data) + assert_match('filename="file02"', data) + assert_match('Content%-Type: ' .. text_plain .. '\r\n', data) + assert_not_match('Content%-Type: application/octet%-stream\r\n', data) +end + +function test_buffer_03() + post = assert(scurl.form{name03 = { + name = 'file03', + data = 'value03', + headers = {"Content-Encoding: gzip"}, + }}) + local data = assert_string(post:get()) + assert_match("\r\n\r\nvalue03\r\n", data) + assert_match('name="name03"', data) + assert_match('filename="file03"', data) + assert_match('Content%-Type: application/octet%-stream\r\n', data) + assert_match('Content%-Encoding: gzip\r\n', data) +end + +function test_buffer_04() + post = assert(scurl.form{name04 = { + name = 'file04', + data = 'value04', + type = text_plain, + headers = {"Content-Encoding: gzip"}, + }}) + + local data = assert_string(post:get()) + assert_match("\r\n\r\nvalue04\r\n", data) + assert_match('name="name04"', data) + assert_match('filename="file04"', data) + assert_match('Content%-Type: ' .. text_plain .. '\r\n', data) + assert_not_match('Content%-Type: application/octet%-stream\r\n', data) + assert_match('Content%-Encoding: gzip\r\n', data) +end + +function test_stream_01() + post = assert(scurl.form{name01 = { + stream = function() end, + length = 128, + }}) + local data = assert_string(post:get()) + assert_match('name="name01"', data) + assert_not_match('filename', data) +end + +function test_stream_02() + post = assert(scurl.form{name02 = { + name = 'file02', + stream = function() end, + length = 128, + }}) + local data = assert_string(post:get()) + assert_match('name="name02"', data) + assert_match('filename="file02"', data) +end + +function test_stream_03() + post = assert(scurl.form{name03 = { + name = 'file03', + stream = function() end, + length = 128, + type = text_plain, + }}) + + local data = assert_string(post:get()) + assert_match('name="name03"', data) + assert_match('filename="file03"', data) + assert_match('Content%-Type: ' .. text_plain .. '\r\n', data) +end + +function test_stream_04() + post = assert(scurl.form{name04 = { + name = 'file04', + stream = function() end, + length = 128, + type = text_plain, + headers = {"Content-Encoding: gzip"}, + }}) + local data = assert_string(post:get()) + assert_match('name="name04"', data) + assert_match('filename="file04"', data) + assert_match('Content%-Type: ' .. text_plain .. '\r\n', data) + assert_match('Content%-Encoding: gzip\r\n', data) +end + +function test_stream_05() + post = assert(scurl.form{name05 = { + stream = { + length = function() return 128 end; + read = function() end; + } + }}) + local data = assert_string(post:get()) + assert_match('name="name05"', data) + assert_not_match('filename', data) +end + +function test_error() + assert_error(function() post = scurl.form{name = {content = 1}} end) + assert_error(function() post = scurl.form{name = {1}} end) + assert_error(function() post = scurl.form{name = {data = {}}} end) + assert_error(function() post = scurl.form{name = {file = true}} end) + assert_error(function() post = scurl.form{name = {stream = function() end}} end) + assert_error(function() post = scurl.form{name = {stream = {}}} end) + assert_error(function() post = scurl.form{name = {stream = { + read=function()end;length=function()end + }}}end) + assert_error(function() post = scurl.form{name = {stream = { + read=function()end;length=function() return "123" end + }}}end) + assert_error(function() post = scurl.form{name = {stream = { + read=function()end;length=function() return "hello" end + }}}end) +end + +function test_ignore_unknown() + post = assert(scurl.form{ + name01 = {}, + name02 = {name = "helo"}, + }) + local data = assert_string(post:get()) + assert_not_match('name="name01"', data) + assert_not_match('name="name02"', data) +end + +function test_empty() + post = assert(scurl.form{}) +end + +end + +RUN() diff --git a/test/test_easy.lua b/test/test_easy.lua index 2710764..7eb55c4 100644 --- a/test/test_easy.lua +++ b/test/test_easy.lua @@ -1,1309 +1,1309 @@ -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 TEST_CASE = assert(lunit.TEST_CASE) -local skip = lunit.skip or function() end - -local curl = require "lcurl" -local scurl = require "lcurl.safe" -local json = require "dkjson" -local path = require "path" -local upath = require "path".new('/') -local utils = require "utils" -local fname = "./test.download" - --- local GET_URL = "http://example.com" --- local POST_URL = "http://httpbin.org/post" -local GET_URL = "http://127.0.0.1:7090/get" -local POST_URL = "http://127.0.0.1:7090/post" - --- print("------------------------------------") --- print("Lua version: " .. (_G.jit and _G.jit.version or _G._VERSION)) --- print("cURL version: " .. curl.version()) --- print("------------------------------------") --- print("") - -local weak_ptr, gc_collect, is_curl_ge, read_file, stream, Stream, dump_request = - utils.import('weak_ptr', 'gc_collect', 'is_curl_ge', 'read_file', 'stream', 'Stream', 'dump_request') - -local null = curl.null - -local ENABLE = true - -local _ENV = TEST_CASE'curl error' if ENABLE then - -function test_eq_with_same_cat() - local e1 = curl.error(curl.ERROR_EASY, curl.E_OK) - local e2 = curl.error(curl.ERROR_EASY, curl.E_OK) - assert_equal(e1, e2) -end - -function test_eq_with_different_cat() - local e1 = curl.error(curl.ERROR_EASY, curl.E_OK) - local e2 = curl.error(curl.ERROR_FORM, curl.E_OK) - - assert_equal(e1:no(), e2:no()) - assert_not_equal(e1, e2) -end - -function test_ctor_cat() - local e - - e = curl.error(curl.ERROR_EASY, curl.E_OK) - assert_equal(e:category(), curl.ERROR_EASY) - assert_equal(e:no(), curl.E_OK) - - e = curl.error(curl.ERROR_MULTI, curl.E_OK) - assert_equal(e:category(), curl.ERROR_MULTI) - assert_equal(e:no(), curl.E_OK) - - e = curl.error(curl.ERROR_SHARE, curl.E_OK) - assert_equal(e:category(), curl.ERROR_SHARE) - assert_equal(e:no(), curl.E_OK) - - e = curl.error(curl.ERROR_FORM, curl.E_OK) - assert_equal(e:category(), curl.ERROR_FORM) - assert_equal(e:no(), curl.E_OK) - - assert_error(function() - curl.error(nil, curl.E_OK) - end) - - assert_error(function() - curl.error('UNKNOWN STRING', curl.E_OK) - end) - -end - -end - -local _ENV = TEST_CASE'write_callback' if ENABLE then - -local c, f - -function teardown() - if f then f:close() end - os.remove(fname) - if c then c:close() end - f, c = nil -end - -function test_write_to_file() - f = assert(io.open(fname, "w+b")) - c = assert(curl.easy{ - url = GET_URL; - writefunction = f; - }) - - assert_equal(c, c:perform()) -end - -function test_write_abort_01() - c = assert(scurl.easy{ - url = GET_URL; - writefunction = function(str) return #str - 1 end; - }) - - local _, e = assert_nil(c:perform()) - assert_equal(curl.error(curl.ERROR_EASY, curl.E_WRITE_ERROR), e) -end - -function test_write_abort_02() - c = assert(scurl.easy{ - url = GET_URL; - writefunction = function(str) return false end; - }) - - local _, e = assert_nil(c:perform()) - assert_equal(curl.error(curl.ERROR_EASY, curl.E_WRITE_ERROR), e) -end - -function test_write_abort_03() - c = assert(scurl.easy{ - url = GET_URL; - writefunction = function(str) return nil, "WRITEERROR" end; - }) - - local _, e = assert_nil(c:perform()) - assert_equal("WRITEERROR", e) -end - -function test_write_abort_04() - c = assert(scurl.easy{ - url = GET_URL; - writefunction = function(str) return nil end; - }) - - local _, e = assert_nil(c:perform()) - assert_equal(curl.error(curl.ERROR_EASY, curl.E_WRITE_ERROR), e) -end - -function test_reset_write_callback() - f = assert(io.open(fname, "w+b")) - c = assert(curl.easy{url = url}) - assert_equal(c, c:setopt_writefunction(f)) - assert_equal(c, c:setopt_writefunction(f.write, f)) - assert_equal(c, c:setopt_writefunction(print)) - assert_equal(c, c:setopt_writefunction(print, null)) - assert_equal(c, c:setopt_writefunction(null)) - assert_equal(c, c:setopt_writefunction(null, nil)) - assert_equal(c, c:setopt_writefunction(null, null)) - assert_error(function()c:setopt_writefunction()end) - assert_error(function()c:setopt_writefunction(nil)end) - assert_error(function()c:setopt_writefunction(nil, f)end) - assert_error(function()c:setopt_writefunction(null, {})end) - assert_error(function()c:setopt_writefunction(print, {}, nil)end) - assert_error(function()c:setopt_writefunction(print, {}, null)end) -end - -function test_write_pass_01() - c = assert(curl.easy{ - url = GET_URL; - writefunction = function(s) return #s end - }) - - assert_equal(c, c:perform()) -end - -function test_write_pass_02() - c = assert(curl.easy{ - url = GET_URL; - writefunction = function() return end - }) - - assert_equal(c, c:perform()) -end - -function test_write_pass_03() - c = assert(curl.easy{ - url = GET_URL; - writefunction = function() return true end - }) - - assert_equal(c, c:perform()) -end - -function test_write_coro() - local co1, co2 - local called - - co1 = coroutine.create(function() - c = assert(curl.easy{ - url = GET_URL; - writefunction = function() - called = coroutine.running() - return true - end - }) - coroutine.yield() - end) - - co2 = coroutine.create(function() - assert_equal(c, c:perform()) - end) - - coroutine.resume(co1) - coroutine.resume(co2) - - assert_equal(co2, called) -end - -function test_write_pass_null_context() - c = assert(curl.easy{ - url = GET_URL; - }) - - local context - assert_equal(c, c:setopt_writefunction(function(ctx) - context = ctx - return true - end, null)) - - assert_equal(c, c:perform()) - assert_equal(null, context) -end - -function test_write_pass_nil_context() - c = assert(curl.easy{ - url = GET_URL; - }) - - local context, called - assert_equal(c, c:setopt_writefunction(function(ctx) - context = ctx - called = true - return true - end, nil)) - - assert_equal(c, c:perform()) - assert_true(called) - assert_nil(context) -end - -end - -local _ENV = TEST_CASE'progress_callback' if ENABLE then - -local c - -local function pass() end - -function teardown() - if f then f:close() end - os.remove(fname) - if c then c:close() end - f, c = nil -end - -function test_abort_01() - c = assert(scurl.easy{ - url = GET_URL, - writefunction = pass, - noprogress = false, - progressfunction = function() return false end - }) - - local _, e = assert_nil(c:perform()) - assert_equal(curl.error(curl.ERROR_EASY, curl.E_ABORTED_BY_CALLBACK), e) -end - -function test_abort_02() - c = assert(scurl.easy{ - url = GET_URL, - writefunction = pass, - noprogress = false, - progressfunction = function() return 0 end - }) - - local _, e = assert_nil(c:perform()) - assert_equal(curl.error(curl.ERROR_EASY, curl.E_ABORTED_BY_CALLBACK), e) -end - -function test_abort_03() - c = assert(scurl.easy{ - url = GET_URL, - writefunction = pass, - noprogress = false, - progressfunction = function() return nil end - }) - - local _, e = assert_nil(c:perform()) - assert_equal(curl.error(curl.ERROR_EASY, curl.E_ABORTED_BY_CALLBACK), e) -end - -function test_abort_04() - c = assert(scurl.easy{ - url = GET_URL, - writefunction = pass, - noprogress = false, - progressfunction = function() return nil, "PROGRESSERROR" end - }) - - local _, e = assert_nil(c:perform()) - assert_equal("PROGRESSERROR", e) -end - -function test_abort_05() - c = assert(scurl.easy{ - url = GET_URL, - writefunction = pass, - noprogress = false, - progressfunction = function() error( "PROGRESSERROR" )end - }) - - assert_error_match("PROGRESSERROR", function() - c:perform() - end) -end - -function test_pass_01() - c = assert(scurl.easy{ - url = GET_URL, - writefunction = pass, - noprogress = false, - progressfunction = function() end - }) - - assert_equal(c, c:perform()) -end - -function test_pass_02() - c = assert(scurl.easy{ - url = GET_URL, - writefunction = pass, - noprogress = false, - progressfunction = function() return true end - }) - - assert_equal(c, c:perform()) -end - -function test_pass_03() - c = assert(scurl.easy{ - url = GET_URL, - writefunction = pass, - noprogress = false, - progressfunction = function() return 1 end - }) - - assert_equal(c, c:perform()) -end - -end - -local _ENV = TEST_CASE'header_callback' if ENABLE then - -local c, f -local function dummy() end - -function teardown() - if c then c:close() end - f, c = nil -end - -function test_header_abort_01() - c = assert(scurl.easy{ - url = GET_URL; - writefunction = dummy, - headerfunction = function(str) return #str - 1 end; - }) - - local _, e = assert_nil(c:perform()) - assert_equal(curl.error(curl.ERROR_EASY, curl.E_WRITE_ERROR), e) -end - -function test_header_abort_02() - c = assert(scurl.easy{ - url = GET_URL; - writefunction = dummy, - headerfunction = function(str) return false end; - }) - - local _, e = assert_nil(c:perform()) - assert_equal(curl.error(curl.ERROR_EASY, curl.E_WRITE_ERROR), e) -end - -function test_header_abort_03() - c = assert(scurl.easy{ - url = GET_URL; - writefunction = dummy, - headerfunction = function(str) return nil, "WRITEERROR" end; - }) - - local _, e = assert_nil(c:perform()) - assert_equal("WRITEERROR", e) -end - -function test_header_abort_04() - c = assert(scurl.easy{ - url = GET_URL; - writefunction = dummy, - headerfunction = function(str) return nil end; - }) - - local _, e = assert_nil(c:perform()) - assert_equal(curl.error(curl.ERROR_EASY, curl.E_WRITE_ERROR), e) -end - -function test_reset_header_callback() - f = {header = function() end} - c = assert(curl.easy{url = url}) - assert_equal(c, c:setopt_headerfunction(f)) - assert_equal(c, c:setopt_headerfunction(f.header, f)) - assert_equal(c, c:setopt_headerfunction(print)) - assert_equal(c, c:setopt_headerfunction(null)) - assert_equal(c, c:setopt_headerfunction(null, nil)) - assert_equal(c, c:setopt_headerfunction(null, null)) - assert_error(function()c:setopt_headerfunction()end) - assert_error(function()c:setopt_headerfunction(nil)end) - assert_error(function()c:setopt_headerfunction(nil, f)end) - assert_error(function()c:setopt_headerfunction(null, {})end) - assert_error(function()c:setopt_headerfunction(print, {}, nil)end) -end - -function test_header_pass_01() - c = assert(curl.easy{ - url = GET_URL; - writefunction = dummy, - headerfunction = function(s) return #s end - }) - - assert_equal(c, c:perform()) -end - -function test_header_pass_02() - c = assert(curl.easy{ - url = GET_URL; - writefunction = dummy, - headerfunction = function() return end - }) - - assert_equal(c, c:perform()) -end - -function test_header_pass_03() - c = assert(curl.easy{ - url = GET_URL; - writefunction = dummy, - headerfunction = function() return true end - }) - - assert_equal(c, c:perform()) -end - - -end - -local _ENV = TEST_CASE'read_stream_callback' if ENABLE and is_curl_ge(7,30,0) then - --- tested on WinXP(x32)/Win8(x64) libcurl/7.37.1 / libcurl/7.30.0 - -local url = POST_URL - -local m, c, f, t - -local function json_data() - return json.decode(table.concat(t)) -end - -function setup() - t = {} - f = assert(scurl.form()) - c = assert(scurl.easy{ - url = url, - timeout = 60, - }) - assert_equal(c, c:setopt_writefunction(table.insert, t)) -end - -function teardown() - if f then f:free() end - if c then c:close() end - if m then m:close() end - t, f, c, m = nil -end - -function test() - assert_equal(f, f:add_stream('SSSSS', stream('X', 128, 13))) - assert_equal(c, c:setopt_httppost(f)) - - -- should be called only stream callback - local read_called - assert_equal(c, c:setopt_readfunction(function() - read_called = true - end)) - - assert_equal(c, c:perform()) - - assert_nil(read_called) - - assert_equal(200, c:getinfo_response_code()) - local data = assert_table(json_data()) - assert_table(data.form) - assert_equal(('X'):rep(128), data.form.SSSSS) -end - -function test_object() - local s = Stream('X', 128, 13) - - assert_equal(f, f:add_stream('SSSSS', s:size(), s)) - assert_equal(c, c:setopt_httppost(f)) - assert_equal(c, c:perform()) - - assert_equal(s, s.called_ctx) - - assert_equal(200, c:getinfo_response_code()) - local data = assert_table(json_data()) - assert_table(data.form) - assert_equal(('X'):rep(128), data.form.SSSSS) -end - -function test_co_multi() - local s = Stream('X', 128, 13) - assert_equal(f, f:add_stream('SSSSS', s:size(), s)) - assert_equal(c, c:setopt_httppost(f)) - - m = assert(scurl.multi()) - assert_equal(m, m:add_handle(c)) - - co = coroutine.create(function() - while 1== m:perform() do end - end) - - coroutine.resume(co) - - assert_equal(co, s.called_co) - - assert_equal(200, c:getinfo_response_code()) - local data = assert_table(json_data()) - assert_table(data.form) - assert_equal(('X'):rep(128), data.form.SSSSS) -end - -function test_co() - local s = Stream('X', 128, 13) - - assert_equal(f, f:add_stream('SSSSS', s:size(), s)) - assert_equal(c, c:setopt_httppost(f)) - - co = coroutine.create(function() - assert_equal(c, c:perform()) - end) - - coroutine.resume(co) - - assert_equal(co, s.called_co) - - assert_equal(200, c:getinfo_response_code()) - local data = assert_table(json_data()) - assert_table(data.form) - assert_equal(('X'):rep(128), data.form.SSSSS) - -end - -function test_abort_01() - assert_equal(f, f:add_stream('SSSSS', 128 * 1024, function() end)) - assert_equal(c, c:setopt_timeout(5)) - assert_equal(c, c:setopt_httppost(f)) - - local _, e = assert_nil(c:perform()) - assert_equal(curl.error(curl.ERROR_EASY, curl.E_OPERATION_TIMEDOUT), e) -end - -function test_abort_02() - assert_equal(f, f:add_stream('SSSSS', 128, function() return nil, "READERROR" end)) - assert_equal(c, c:setopt_httppost(f)) - - local _, e = assert_nil(c:perform()) - assert_equal("READERROR", e) -end - -function test_abort_03() - assert_equal(f, f:add_stream('SSSSS', 128, function() return 1 end)) - assert_equal(c, c:setopt_httppost(f)) - - local _, e = assert_nil(c:perform()) - assert_equal(curl.error(curl.ERROR_EASY, curl.E_ABORTED_BY_CALLBACK), e) -end - -function test_abort_04() - assert_equal(f, f:add_stream('SSSSS', 128, function() return true end)) - assert_equal(c, c:setopt_httppost(f)) - - local _, e = assert_nil(c:perform()) - assert_equal(curl.error(curl.ERROR_EASY, curl.E_ABORTED_BY_CALLBACK), e) -end - -function test_abort_05() - assert_equal(f, f:add_stream('SSSSS', 128, function() error("READERROR") end)) - assert_equal(c, c:setopt_httppost(f)) - - assert_error_match("READERROR", function() c:perform() end) -end - -function test_abort_06() - assert_equal(f, f:add_stream('SSSSS', 128, function() return false end)) - assert_equal(c, c:setopt_httppost(f)) - - local _, e = assert_nil(c:perform()) - assert_equal(curl.error(curl.ERROR_EASY, curl.E_ABORTED_BY_CALLBACK), e) -end - -function test_pass_01() - assert_equal(c, c:setopt_timeout(10)) - assert_equal(f, f:add_stream('SSSSS', 128, function() return nil end)) - assert_equal(c, c:setopt_httppost(f)) - - local _, e = assert_nil(c:perform()) - assert_equal(curl.error(curl.ERROR_EASY, curl.E_OPERATION_TIMEDOUT), e) -end - -function test_pause() - local counter = 0 - assert_equal(f, f:add_stream('SSSSS', 128, function() - if counter == 0 then - counter = counter + 1 - return curl.READFUNC_PAUSE - end - if counter == 1 then - counter = counter + 1 - return ('X'):rep(128) - end - return '' - end)) - - assert_equal(c, c:setopt_progressfunction(function() - if counter == 1 then - c:pause(curl.PAUSE_CONT) - end - end)) - - assert_equal(c, c:setopt_noprogress(false)) - - assert_equal(c, c:setopt_httppost(f)) - - assert_equal(c, c:perform()) - assert_equal(200, c:getinfo_response_code()) - local data = assert_table(json_data()) - assert_table(data.form) - assert_equal(('X'):rep(128), data.form.SSSSS) -end - -end - -local _ENV = TEST_CASE'read_callback' if ENABLE then - -local uname = upath:normalize(path.fullpath(fname)) - -local url = "FILE:///" .. uname - -local c - -function setup() - c = assert(scurl.easy{ - url = url, - upload = true, - }) -end - -function teardown() - os.remove(fname) - if c then c:close() end - c = nil -end - -function test_abort_01() --- assert_equal(c, c:setopt_readfunction(function() end)) --- --- local _, e = assert_nil(c:perform()) --- assert_equal(curl.error(curl.ERROR_EASY, curl.E_ABORTED_BY_CALLBACK), e) -end - -function test_abort_02() - assert_equal(c, c:setopt_readfunction(function() return nil, "READERROR" end)) - - local _, e = assert_nil(c:perform()) - assert_equal("READERROR", e) -end - -function test_abort_03() - assert_equal(c, c:setopt_readfunction(function() return 1 end)) - - local _, e = assert_nil(c:perform()) - assert_equal(curl.error(curl.ERROR_EASY, curl.E_ABORTED_BY_CALLBACK), e) -end - -function test_abort_04() - assert_equal(c, c:setopt_readfunction(function() return true end)) - - local _, e = assert_nil(c:perform()) - assert_equal(curl.error(curl.ERROR_EASY, curl.E_ABORTED_BY_CALLBACK), e) -end - -function test_abort_05() - assert_equal(c, c:setopt_readfunction(function() error("READERROR") end)) - - assert_error_match("READERROR", function() c:perform() end) -end - -function test_abort_06() - assert_equal(c, c:setopt_readfunction(function() return false end)) - - local _, e = assert_nil(c:perform()) - assert_equal(curl.error(curl.ERROR_EASY, curl.E_ABORTED_BY_CALLBACK), e) -end - -function test_pause() - --- BUG? --- c:perform() returns curl.E_READ_ERROR after readfunction return curl.READFUNC_PAUSE --- --- OS version : Linux Mint 17 (x86_64) --- cURL version : libcurl/7.35.0 OpenSSL/1.0.1f zlib/1.2.8 libidn/1.28 librtmp/2.3 --- version_info("host"): x86_64-pc-linux-gnu --- --- OS version : Windows XP (x86_64) --- cURL version : libcurl/7.38.0 OpenSSL/1.0.1c zlib/1.2.7 WinIDN --- cURL version : libcurl/7.37.1 OpenSSL/1.0.1c zlib/1.2.7 WinIDN --- version_info("host"): i386-pc-win32 --- --- Works correctly on --- (same binary as with libcurl 7.38.0/7.37.1) --- --- OS version : Windows XP (x86_64) --- cURL version : libcurl/7.30.0 OpenSSL/0.9.8y zlib/1.2.7 --- version_info("host"): i386-pc-win32 --- - - local counter = 0 - assert_equal(c, c:setopt_readfunction(function() - if counter == 0 then - counter = counter + 1 - return curl.READFUNC_PAUSE - end - if counter == 1 then - counter = counter + 1 - return ('X'):rep(128) - end - return '' - end)) - - assert_equal(c, c:setopt_progressfunction(function() - if counter == 1 then - c:pause(curl.PAUSE_CONT) - end - end)) - - assert_equal(c, c:setopt_noprogress(false)) - - local ok, err = c:perform() - - if (not ok) and err:name() == "READ_ERROR" then - skip("TODO check pause on readfunction") - end - - assert_equal(c, ok, err) - - assert_equal(0, c:getinfo_response_code()) -end - -function test_readbuffer() - local flag = false - local N - assert_equal(c, c:setopt_readfunction(function(n) - if not flag then - flag = true - N = math.floor(n*2 + n/3) - assert(N > n) - return ("s"):rep(N) - end - return '' - end)) - - assert_equal(c, c:perform()) - c:close() - local data = read_file(fname) - assert_equal(N, #data) - assert_equal(("s"):rep(N), data) -end - -function test_pass_01() - -- We need this to support file:read() method which returns nil as EOF - assert_equal(c, c:setopt_readfunction(function() return nil end)) - - assert_equal(c, c:perform()) - c:close() - local data = read_file(fname) - assert_equal(0, #data) -end - -function test_pass_02() - local counter = 10 - assert_equal(c, c:setopt_readfunction(function() - if counter > 0 then - counter = counter - 1 - return 'a' - end - end)) - - assert_equal(c, c:perform()) - c:close() - local data = read_file(fname) - assert_equal(('a'):rep(10), data) -end - -end - -local _ENV = TEST_CASE'escape' if ENABLE then - -local c - -function teardown() - if c then c:close() end - f, c = nil -end - -function test() - local e = "This%2Bis%2Ba%2Bsimple%2B%2526%2Bshort%2Btest." - local d = "This+is+a+simple+%26+short+test." - c = assert(curl.easy()) - assert_equal(e, c:escape(d)) - assert_equal(d, c:unescape(e)) -end - -end - -local _ENV = TEST_CASE'setopt_form' if ENABLE then - -local c - -function teardown() - if c then c:close() end - c = nil -end - -function test() - local pfrom, e - do - local form = curl.form() - e = curl.easy{httppost = form} - pfrom = weak_ptr(form) - end - - gc_collect() - assert(pfrom.value) - - e:setopt_httppost(curl.form()) - - gc_collect() - assert(not pfrom.value) -end - -function test_unset() - local pfrom, e - do - local form = curl.form() - e = curl.easy{httppost = form} - pfrom = weak_ptr(form) - end - - gc_collect() - assert(pfrom.value) - - assert_equal(e, e:unsetopt_httppost()) - - gc_collect() - assert(not pfrom.value) -end - -function test_reset() - local pfrom, e - do - local form = curl.form() - e = curl.easy{httppost = form} - pform = weak_ptr(form) - end - - gc_collect() - assert(pform.value) - - assert_equal(e, e:reset()) - - gc_collect() - assert(not pform.value) -end - -end - -local _ENV = TEST_CASE'setopt_postfields' if ENABLE then - -local c - -function teardown() - if c then c:close() end - c = nil -end - -function test() - - do local fields = {} - for i = 1, 100 do fields[#fields + 1] = string.format('key%d=value%d', i, i) end - fields = table.concat(fields, '&') - c = assert(curl.easy{ - url = POST_URL, - postfields = fields, - writefunction = function()end, - }) - end - - -- call gc to try clear `fields` string - for i = 1, 4 do collectgarbage"collect" end - - c:perform() -end - -function test_unset() - local pfields - - do local fields = {} - for i = 1, 100 do fields[#fields + 1] = string.format('key%d=value%d', i, i) end - fields = table.concat(fields, '&') - c = assert(curl.easy{ - url = POST_URL, - postfields = fields, - writefunction = function()end, - }) - pfields = weak_ptr(fields) - end - - -- call gc to try clear `fields` string - for i = 1, 4 do collectgarbage"collect" end - assert_string(pfields.value) - - assert_equal(c, c:unsetopt_postfields()) - - -- @todo check internal storage because gc really do not clear `weak` string - -- for i = 1, 4 do collectgarbage"collect" end - -- assert_nil(pfields.value) - - -- c:perform() -end - -end - -local _ENV = TEST_CASE'setopt_user_data' if ENABLE then - -local c - -function teardown() - if c then c:close() end - c = nil -end - -function test_data() - c = assert(curl.easy()) - assert_nil(c:getdata()) - c:setdata("hello") - assert_equal("hello", c:getdata()) -end - -function test_cleanup() - local ptr do - local t = {} - local e = curl.easy():setdata(t) - ptr = weak_ptr(t) - gc_collect() - - assert_equal(t, ptr.value) - end - - gc_collect() - assert_nil(ptr.value) -end - -end - -local _ENV = TEST_CASE'multi_add_remove' if ENABLE then - -local m, c - -function setup() - m = assert(scurl.multi()) -end - -function teardown() - if c then c:close() end - if m then m:close() end - m, c = nil -end - -function test_remove_unknow_easy() - c = assert(scurl.easy()) - assert_equal(m, m:remove_handle(c)) -end - -function test_double_remove_easy() - c = assert(scurl.easy()) - assert_equal(m, m:add_handle(c)) - assert_equal(m, m:remove_handle(c)) - assert_equal(m, m:remove_handle(c)) -end - -function test_double_add_easy() - c = assert(scurl.easy()) - assert_equal(m, m:add_handle(c)) - assert_nil(m:add_handle(c)) -end - -end - -local _ENV = TEST_CASE'unset_callback_ctx' if ENABLE then - -local HSTS = curl.version_info().features.HSTS - -local c - -function setup() - c = assert(scurl.easy()) -end - -function teardown() - if c then c:close() end - c = nil -end - -local function test_cb(name) - local set, unset = 'setopt_' .. name, 'unsetopt_' .. name - - set = assert_function(c[set], set) - unset = assert_function(c[unset], unset) - - local pctx - do local ctx = {} - pctx = weak_ptr(ctx) - assert(set(c, function() end, ctx)) - end - - gc_collect() - assert_table(pctx.value) - - unset(c) - - gc_collect() - assert_nil(pctx.value) - - do local ctx = {} - pctx = weak_ptr(ctx) - assert(set(c, function() end, ctx)) - end - - gc_collect() - assert_table(pctx.value) - - c:reset() - - gc_collect() - assert_nil(pctx.value) -end - -function test_read() test_cb('readfunction') end -function test_write() test_cb('writefunction') end -function test_header() test_cb('headerfunction') end -function test_progress() test_cb('progressfunction') end -function test_seek() test_cb('seekfunction') end -function test_debug() test_cb('debugfunction') end -function test_fnmatch() test_cb('fnmatch_function') end -function test_chunk_bgn() test_cb('chunk_bgn_function') end -function test_chunk_end() test_cb('chunk_end_function') end - -if curl.OPT_HSTSREADFUNCTION and HSTS then -function test_hstsreadfunction() test_cb('hstsreadfunction') end -function test_hstswritefunction() test_cb('hstswritefunction') end -end - -end - -local _ENV = TEST_CASE'set_slist' if ENABLE then - -local c - -function teardown() - if c then c:close() end - c = nil -end - -function test_set() - c = curl.easy() - c:setopt_httpheader({'X-Custom: value'}) - local body, headers = assert_string(dump_request(c)) - assert_match("X%-Custom:%s*value\r\n", headers) -end - -function test_unset() - c = curl.easy() - c:setopt_httpheader({'X-Custom: value'}) - c:unsetopt_httpheader() - local body, headers = assert_string(dump_request(c)) - assert_not_match("X%-Custom:%s*value\r\n", headers) -end - -function test_set_empty_array() - c = curl.easy() - c:setopt_httpheader({'X-Custom: value'}) - c:setopt_httpheader({}) - local body, headers = assert_string(dump_request(c)) - assert_not_match("X%-Custom:%s*value\r\n", headers) -end - -function test_reset_slist() - c = curl.easy { - httpheader = {'X-Foo: 1'}, - resolve = {'example.com:80:127.0.0.1'} - } - - c:reset() - - c:setopt{ - httpheader = {'X-Foo: 2'}, - resolve = {'example.com:80:127.0.0.1'} - } - - local body, headers = assert_string(dump_request(c)) - assert_match("X%-Foo:%s2\r\n", headers) -end - -end - -local _ENV = TEST_CASE'set_null' if ENABLE then - -local c, m - -function teardown() - if c then c:close() end - if m then m:close() end - m, c = nil -end - -function test_string() - c = curl.easy() - c:setopt_accept_encoding('gzip') - local body, headers = assert_string(dump_request(c)) - assert_match("Accept%-Encoding:%s*gzip", headers) - - c:setopt_accept_encoding(null) - body, headers = assert_string(dump_request(c)) - assert_not_match("Accept%-Encoding:%s*gzip", headers) -end - -function test_string_via_table() - c = curl.easy() - c:setopt_accept_encoding('gzip') - local body, headers = assert_string(dump_request(c)) - assert_match("Accept%-Encoding:%s*gzip", headers) - - c:setopt{ accept_encoding = null } - body, headers = assert_string(dump_request(c)) - assert_not_match("Accept%-Encoding:%s*gzip", headers) -end - -function test_slist() - c = curl.easy() - c:setopt_httpheader({'X-Custom: value'}) - c:setopt_httpheader(null) - local body, headers = assert_string(dump_request(c)) - assert_not_match("X%-Custom:%s*value\r\n", headers) -end - -function test_slist_via_table() - c = curl.easy() - c:setopt_httpheader({'X-Custom: value'}) - c:setopt{httpheader = null} - local body, headers = assert_string(dump_request(c)) - assert_not_match("X%-Custom:%s*value\r\n", headers) -end - -function test_multi_set_array() - m = curl.multi() - m:setopt_pipelining_site_bl{ - '127.0.0.1' - } - assert_equal(m, m:setopt_pipelining_site_bl(null)) -end - -end - -local _ENV = TEST_CASE'trailer_callback' if ENABLE and is_curl_ge(7,64,0) then - -local url = POST_URL - -local m, c, t - -local function json_data() - return json.decode(table.concat(t)) -end - -local treader = function(t) - local i = 0 - return function() - i = i + 1 - return t[i] - end -end - -function setup() - t = {} - c = assert(scurl.easy{ - url = url, - post = true, - httpheader = {"Transfer-Encoding: chunked"}, - readfunction = treader {'a=1&', 'b=2&'}, - timeout = 60, - }) - assert_equal(c, c:setopt_writefunction(table.insert, t)) -end - -function teardown() - if c then c:close() end - if m then m:close() end - t, c, m = nil -end - -local empty_responses = { - {'no_response', function() end}, - {'nil_response', function() return nil end}, - {'null_response', function() return curl.null end}, - {'true_response', function() return true end}, - {'empty_array', function() return {} end}, -} - -local abort_responses = { - {'false_response', function() return false end}, - {'nil_with_error_response', function() return nil, 'error message' end}, - {'numeric_response_0', function() return 0 end}, - {'numeric_response_1', function() return 1 end}, -} - -for _, response in ipairs(empty_responses) do - _ENV[ 'test_' .. response[1] ] = function() - local trailer_called = 0 - assert_equal(c, c:setopt_trailerfunction(function() - trailer_called = trailer_called + 1 - return response[2]() - end)) - - assert_equal(c, c:perform()) - - assert_equal(1, trailer_called) - - assert_equal(200, c:getinfo_response_code()) - local data = assert_table(json_data()) - - assert_equal('1', data.form.a) - assert_equal('2', data.form.b) - end -end - -for _, response in ipairs(abort_responses) do - _ENV[ 'test_' .. response[1] ] = function() - local trailer_called = 0 - assert_equal(c, c:setopt_trailerfunction(function() - trailer_called = trailer_called + 1 - return response[2]() - end)) - - local ok, err = assert_nil(c:perform()) - assert_equal(1, trailer_called) - assert_equal(curl.error(curl.ERROR_EASY, curl.E_ABORTED_BY_CALLBACK), err) - end -end - -function test_send_header() - local trailer_called = 0 - assert_equal(c, c:setopt_trailerfunction(function() - trailer_called = trailer_called + 1 - return {'x-trailer-header: value'} - end)) - - assert_equal(c, c:perform()) - - assert_equal(1, trailer_called) - - assert_equal(200, c:getinfo_response_code()) - local data = assert_table(json_data()) - - assert_equal('1', data.form.a) - assert_equal('2', data.form.b) - assert_equal('value', data.headers['x-trailer-header']) -end - -end - -RUN() +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 TEST_CASE = assert(lunit.TEST_CASE) +local skip = lunit.skip or function() end + +local curl = require "lcurl" +local scurl = require "lcurl.safe" +local json = require "dkjson" +local path = require "path" +local upath = require "path".new('/') +local utils = require "utils" +local fname = "./test.download" + +-- local GET_URL = "http://example.com" +-- local POST_URL = "http://httpbin.org/post" +local GET_URL = "http://127.0.0.1:7090/get" +local POST_URL = "http://127.0.0.1:7090/post" + +-- print("------------------------------------") +-- print("Lua version: " .. (_G.jit and _G.jit.version or _G._VERSION)) +-- print("cURL version: " .. curl.version()) +-- print("------------------------------------") +-- print("") + +local weak_ptr, gc_collect, is_curl_ge, read_file, stream, Stream, dump_request = + utils.import('weak_ptr', 'gc_collect', 'is_curl_ge', 'read_file', 'stream', 'Stream', 'dump_request') + +local null = curl.null + +local ENABLE = true + +local _ENV = TEST_CASE'curl error' if ENABLE then + +function test_eq_with_same_cat() + local e1 = curl.error(curl.ERROR_EASY, curl.E_OK) + local e2 = curl.error(curl.ERROR_EASY, curl.E_OK) + assert_equal(e1, e2) +end + +function test_eq_with_different_cat() + local e1 = curl.error(curl.ERROR_EASY, curl.E_OK) + local e2 = curl.error(curl.ERROR_FORM, curl.E_OK) + + assert_equal(e1:no(), e2:no()) + assert_not_equal(e1, e2) +end + +function test_ctor_cat() + local e + + e = curl.error(curl.ERROR_EASY, curl.E_OK) + assert_equal(e:category(), curl.ERROR_EASY) + assert_equal(e:no(), curl.E_OK) + + e = curl.error(curl.ERROR_MULTI, curl.E_OK) + assert_equal(e:category(), curl.ERROR_MULTI) + assert_equal(e:no(), curl.E_OK) + + e = curl.error(curl.ERROR_SHARE, curl.E_OK) + assert_equal(e:category(), curl.ERROR_SHARE) + assert_equal(e:no(), curl.E_OK) + + e = curl.error(curl.ERROR_FORM, curl.E_OK) + assert_equal(e:category(), curl.ERROR_FORM) + assert_equal(e:no(), curl.E_OK) + + assert_error(function() + curl.error(nil, curl.E_OK) + end) + + assert_error(function() + curl.error('UNKNOWN STRING', curl.E_OK) + end) + +end + +end + +local _ENV = TEST_CASE'write_callback' if ENABLE then + +local c, f + +function teardown() + if f then f:close() end + os.remove(fname) + if c then c:close() end + f, c = nil +end + +function test_write_to_file() + f = assert(io.open(fname, "w+b")) + c = assert(curl.easy{ + url = GET_URL; + writefunction = f; + }) + + assert_equal(c, c:perform()) +end + +function test_write_abort_01() + c = assert(scurl.easy{ + url = GET_URL; + writefunction = function(str) return #str - 1 end; + }) + + local _, e = assert_nil(c:perform()) + assert_equal(curl.error(curl.ERROR_EASY, curl.E_WRITE_ERROR), e) +end + +function test_write_abort_02() + c = assert(scurl.easy{ + url = GET_URL; + writefunction = function(str) return false end; + }) + + local _, e = assert_nil(c:perform()) + assert_equal(curl.error(curl.ERROR_EASY, curl.E_WRITE_ERROR), e) +end + +function test_write_abort_03() + c = assert(scurl.easy{ + url = GET_URL; + writefunction = function(str) return nil, "WRITEERROR" end; + }) + + local _, e = assert_nil(c:perform()) + assert_equal("WRITEERROR", e) +end + +function test_write_abort_04() + c = assert(scurl.easy{ + url = GET_URL; + writefunction = function(str) return nil end; + }) + + local _, e = assert_nil(c:perform()) + assert_equal(curl.error(curl.ERROR_EASY, curl.E_WRITE_ERROR), e) +end + +function test_reset_write_callback() + f = assert(io.open(fname, "w+b")) + c = assert(curl.easy{url = url}) + assert_equal(c, c:setopt_writefunction(f)) + assert_equal(c, c:setopt_writefunction(f.write, f)) + assert_equal(c, c:setopt_writefunction(print)) + assert_equal(c, c:setopt_writefunction(print, null)) + assert_equal(c, c:setopt_writefunction(null)) + assert_equal(c, c:setopt_writefunction(null, nil)) + assert_equal(c, c:setopt_writefunction(null, null)) + assert_error(function()c:setopt_writefunction()end) + assert_error(function()c:setopt_writefunction(nil)end) + assert_error(function()c:setopt_writefunction(nil, f)end) + assert_error(function()c:setopt_writefunction(null, {})end) + assert_error(function()c:setopt_writefunction(print, {}, nil)end) + assert_error(function()c:setopt_writefunction(print, {}, null)end) +end + +function test_write_pass_01() + c = assert(curl.easy{ + url = GET_URL; + writefunction = function(s) return #s end + }) + + assert_equal(c, c:perform()) +end + +function test_write_pass_02() + c = assert(curl.easy{ + url = GET_URL; + writefunction = function() return end + }) + + assert_equal(c, c:perform()) +end + +function test_write_pass_03() + c = assert(curl.easy{ + url = GET_URL; + writefunction = function() return true end + }) + + assert_equal(c, c:perform()) +end + +function test_write_coro() + local co1, co2 + local called + + co1 = coroutine.create(function() + c = assert(curl.easy{ + url = GET_URL; + writefunction = function() + called = coroutine.running() + return true + end + }) + coroutine.yield() + end) + + co2 = coroutine.create(function() + assert_equal(c, c:perform()) + end) + + coroutine.resume(co1) + coroutine.resume(co2) + + assert_equal(co2, called) +end + +function test_write_pass_null_context() + c = assert(curl.easy{ + url = GET_URL; + }) + + local context + assert_equal(c, c:setopt_writefunction(function(ctx) + context = ctx + return true + end, null)) + + assert_equal(c, c:perform()) + assert_equal(null, context) +end + +function test_write_pass_nil_context() + c = assert(curl.easy{ + url = GET_URL; + }) + + local context, called + assert_equal(c, c:setopt_writefunction(function(ctx) + context = ctx + called = true + return true + end, nil)) + + assert_equal(c, c:perform()) + assert_true(called) + assert_nil(context) +end + +end + +local _ENV = TEST_CASE'progress_callback' if ENABLE then + +local c + +local function pass() end + +function teardown() + if f then f:close() end + os.remove(fname) + if c then c:close() end + f, c = nil +end + +function test_abort_01() + c = assert(scurl.easy{ + url = GET_URL, + writefunction = pass, + noprogress = false, + progressfunction = function() return false end + }) + + local _, e = assert_nil(c:perform()) + assert_equal(curl.error(curl.ERROR_EASY, curl.E_ABORTED_BY_CALLBACK), e) +end + +function test_abort_02() + c = assert(scurl.easy{ + url = GET_URL, + writefunction = pass, + noprogress = false, + progressfunction = function() return 0 end + }) + + local _, e = assert_nil(c:perform()) + assert_equal(curl.error(curl.ERROR_EASY, curl.E_ABORTED_BY_CALLBACK), e) +end + +function test_abort_03() + c = assert(scurl.easy{ + url = GET_URL, + writefunction = pass, + noprogress = false, + progressfunction = function() return nil end + }) + + local _, e = assert_nil(c:perform()) + assert_equal(curl.error(curl.ERROR_EASY, curl.E_ABORTED_BY_CALLBACK), e) +end + +function test_abort_04() + c = assert(scurl.easy{ + url = GET_URL, + writefunction = pass, + noprogress = false, + progressfunction = function() return nil, "PROGRESSERROR" end + }) + + local _, e = assert_nil(c:perform()) + assert_equal("PROGRESSERROR", e) +end + +function test_abort_05() + c = assert(scurl.easy{ + url = GET_URL, + writefunction = pass, + noprogress = false, + progressfunction = function() error( "PROGRESSERROR" )end + }) + + assert_error_match("PROGRESSERROR", function() + c:perform() + end) +end + +function test_pass_01() + c = assert(scurl.easy{ + url = GET_URL, + writefunction = pass, + noprogress = false, + progressfunction = function() end + }) + + assert_equal(c, c:perform()) +end + +function test_pass_02() + c = assert(scurl.easy{ + url = GET_URL, + writefunction = pass, + noprogress = false, + progressfunction = function() return true end + }) + + assert_equal(c, c:perform()) +end + +function test_pass_03() + c = assert(scurl.easy{ + url = GET_URL, + writefunction = pass, + noprogress = false, + progressfunction = function() return 1 end + }) + + assert_equal(c, c:perform()) +end + +end + +local _ENV = TEST_CASE'header_callback' if ENABLE then + +local c, f +local function dummy() end + +function teardown() + if c then c:close() end + f, c = nil +end + +function test_header_abort_01() + c = assert(scurl.easy{ + url = GET_URL; + writefunction = dummy, + headerfunction = function(str) return #str - 1 end; + }) + + local _, e = assert_nil(c:perform()) + assert_equal(curl.error(curl.ERROR_EASY, curl.E_WRITE_ERROR), e) +end + +function test_header_abort_02() + c = assert(scurl.easy{ + url = GET_URL; + writefunction = dummy, + headerfunction = function(str) return false end; + }) + + local _, e = assert_nil(c:perform()) + assert_equal(curl.error(curl.ERROR_EASY, curl.E_WRITE_ERROR), e) +end + +function test_header_abort_03() + c = assert(scurl.easy{ + url = GET_URL; + writefunction = dummy, + headerfunction = function(str) return nil, "WRITEERROR" end; + }) + + local _, e = assert_nil(c:perform()) + assert_equal("WRITEERROR", e) +end + +function test_header_abort_04() + c = assert(scurl.easy{ + url = GET_URL; + writefunction = dummy, + headerfunction = function(str) return nil end; + }) + + local _, e = assert_nil(c:perform()) + assert_equal(curl.error(curl.ERROR_EASY, curl.E_WRITE_ERROR), e) +end + +function test_reset_header_callback() + f = {header = function() end} + c = assert(curl.easy{url = url}) + assert_equal(c, c:setopt_headerfunction(f)) + assert_equal(c, c:setopt_headerfunction(f.header, f)) + assert_equal(c, c:setopt_headerfunction(print)) + assert_equal(c, c:setopt_headerfunction(null)) + assert_equal(c, c:setopt_headerfunction(null, nil)) + assert_equal(c, c:setopt_headerfunction(null, null)) + assert_error(function()c:setopt_headerfunction()end) + assert_error(function()c:setopt_headerfunction(nil)end) + assert_error(function()c:setopt_headerfunction(nil, f)end) + assert_error(function()c:setopt_headerfunction(null, {})end) + assert_error(function()c:setopt_headerfunction(print, {}, nil)end) +end + +function test_header_pass_01() + c = assert(curl.easy{ + url = GET_URL; + writefunction = dummy, + headerfunction = function(s) return #s end + }) + + assert_equal(c, c:perform()) +end + +function test_header_pass_02() + c = assert(curl.easy{ + url = GET_URL; + writefunction = dummy, + headerfunction = function() return end + }) + + assert_equal(c, c:perform()) +end + +function test_header_pass_03() + c = assert(curl.easy{ + url = GET_URL; + writefunction = dummy, + headerfunction = function() return true end + }) + + assert_equal(c, c:perform()) +end + + +end + +local _ENV = TEST_CASE'read_stream_callback' if ENABLE and is_curl_ge(7,30,0) then + +-- tested on WinXP(x32)/Win8(x64) libcurl/7.37.1 / libcurl/7.30.0 + +local url = POST_URL + +local m, c, f, t + +local function json_data() + return json.decode(table.concat(t)) +end + +function setup() + t = {} + f = assert(scurl.form()) + c = assert(scurl.easy{ + url = url, + timeout = 60, + }) + assert_equal(c, c:setopt_writefunction(table.insert, t)) +end + +function teardown() + if f then f:free() end + if c then c:close() end + if m then m:close() end + t, f, c, m = nil +end + +function test() + assert_equal(f, f:add_stream('SSSSS', stream('X', 128, 13))) + assert_equal(c, c:setopt_httppost(f)) + + -- should be called only stream callback + local read_called + assert_equal(c, c:setopt_readfunction(function() + read_called = true + end)) + + assert_equal(c, c:perform()) + + assert_nil(read_called) + + assert_equal(200, c:getinfo_response_code()) + local data = assert_table(json_data()) + assert_table(data.form) + assert_equal(('X'):rep(128), data.form.SSSSS) +end + +function test_object() + local s = Stream('X', 128, 13) + + assert_equal(f, f:add_stream('SSSSS', s:size(), s)) + assert_equal(c, c:setopt_httppost(f)) + assert_equal(c, c:perform()) + + assert_equal(s, s.called_ctx) + + assert_equal(200, c:getinfo_response_code()) + local data = assert_table(json_data()) + assert_table(data.form) + assert_equal(('X'):rep(128), data.form.SSSSS) +end + +function test_co_multi() + local s = Stream('X', 128, 13) + assert_equal(f, f:add_stream('SSSSS', s:size(), s)) + assert_equal(c, c:setopt_httppost(f)) + + m = assert(scurl.multi()) + assert_equal(m, m:add_handle(c)) + + co = coroutine.create(function() + while 1== m:perform() do end + end) + + coroutine.resume(co) + + assert_equal(co, s.called_co) + + assert_equal(200, c:getinfo_response_code()) + local data = assert_table(json_data()) + assert_table(data.form) + assert_equal(('X'):rep(128), data.form.SSSSS) +end + +function test_co() + local s = Stream('X', 128, 13) + + assert_equal(f, f:add_stream('SSSSS', s:size(), s)) + assert_equal(c, c:setopt_httppost(f)) + + co = coroutine.create(function() + assert_equal(c, c:perform()) + end) + + coroutine.resume(co) + + assert_equal(co, s.called_co) + + assert_equal(200, c:getinfo_response_code()) + local data = assert_table(json_data()) + assert_table(data.form) + assert_equal(('X'):rep(128), data.form.SSSSS) + +end + +function test_abort_01() + assert_equal(f, f:add_stream('SSSSS', 128 * 1024, function() end)) + assert_equal(c, c:setopt_timeout(5)) + assert_equal(c, c:setopt_httppost(f)) + + local _, e = assert_nil(c:perform()) + assert_equal(curl.error(curl.ERROR_EASY, curl.E_OPERATION_TIMEDOUT), e) +end + +function test_abort_02() + assert_equal(f, f:add_stream('SSSSS', 128, function() return nil, "READERROR" end)) + assert_equal(c, c:setopt_httppost(f)) + + local _, e = assert_nil(c:perform()) + assert_equal("READERROR", e) +end + +function test_abort_03() + assert_equal(f, f:add_stream('SSSSS', 128, function() return 1 end)) + assert_equal(c, c:setopt_httppost(f)) + + local _, e = assert_nil(c:perform()) + assert_equal(curl.error(curl.ERROR_EASY, curl.E_ABORTED_BY_CALLBACK), e) +end + +function test_abort_04() + assert_equal(f, f:add_stream('SSSSS', 128, function() return true end)) + assert_equal(c, c:setopt_httppost(f)) + + local _, e = assert_nil(c:perform()) + assert_equal(curl.error(curl.ERROR_EASY, curl.E_ABORTED_BY_CALLBACK), e) +end + +function test_abort_05() + assert_equal(f, f:add_stream('SSSSS', 128, function() error("READERROR") end)) + assert_equal(c, c:setopt_httppost(f)) + + assert_error_match("READERROR", function() c:perform() end) +end + +function test_abort_06() + assert_equal(f, f:add_stream('SSSSS', 128, function() return false end)) + assert_equal(c, c:setopt_httppost(f)) + + local _, e = assert_nil(c:perform()) + assert_equal(curl.error(curl.ERROR_EASY, curl.E_ABORTED_BY_CALLBACK), e) +end + +function test_pass_01() + assert_equal(c, c:setopt_timeout(10)) + assert_equal(f, f:add_stream('SSSSS', 128, function() return nil end)) + assert_equal(c, c:setopt_httppost(f)) + + local _, e = assert_nil(c:perform()) + assert_equal(curl.error(curl.ERROR_EASY, curl.E_OPERATION_TIMEDOUT), e) +end + +function test_pause() + local counter = 0 + assert_equal(f, f:add_stream('SSSSS', 128, function() + if counter == 0 then + counter = counter + 1 + return curl.READFUNC_PAUSE + end + if counter == 1 then + counter = counter + 1 + return ('X'):rep(128) + end + return '' + end)) + + assert_equal(c, c:setopt_progressfunction(function() + if counter == 1 then + c:pause(curl.PAUSE_CONT) + end + end)) + + assert_equal(c, c:setopt_noprogress(false)) + + assert_equal(c, c:setopt_httppost(f)) + + assert_equal(c, c:perform()) + assert_equal(200, c:getinfo_response_code()) + local data = assert_table(json_data()) + assert_table(data.form) + assert_equal(('X'):rep(128), data.form.SSSSS) +end + +end + +local _ENV = TEST_CASE'read_callback' if ENABLE then + +local uname = upath:normalize(path.fullpath(fname)) + +local url = "FILE:///" .. uname + +local c + +function setup() + c = assert(scurl.easy{ + url = url, + upload = true, + }) +end + +function teardown() + os.remove(fname) + if c then c:close() end + c = nil +end + +function test_abort_01() +-- assert_equal(c, c:setopt_readfunction(function() end)) +-- +-- local _, e = assert_nil(c:perform()) +-- assert_equal(curl.error(curl.ERROR_EASY, curl.E_ABORTED_BY_CALLBACK), e) +end + +function test_abort_02() + assert_equal(c, c:setopt_readfunction(function() return nil, "READERROR" end)) + + local _, e = assert_nil(c:perform()) + assert_equal("READERROR", e) +end + +function test_abort_03() + assert_equal(c, c:setopt_readfunction(function() return 1 end)) + + local _, e = assert_nil(c:perform()) + assert_equal(curl.error(curl.ERROR_EASY, curl.E_ABORTED_BY_CALLBACK), e) +end + +function test_abort_04() + assert_equal(c, c:setopt_readfunction(function() return true end)) + + local _, e = assert_nil(c:perform()) + assert_equal(curl.error(curl.ERROR_EASY, curl.E_ABORTED_BY_CALLBACK), e) +end + +function test_abort_05() + assert_equal(c, c:setopt_readfunction(function() error("READERROR") end)) + + assert_error_match("READERROR", function() c:perform() end) +end + +function test_abort_06() + assert_equal(c, c:setopt_readfunction(function() return false end)) + + local _, e = assert_nil(c:perform()) + assert_equal(curl.error(curl.ERROR_EASY, curl.E_ABORTED_BY_CALLBACK), e) +end + +function test_pause() + +-- BUG? +-- c:perform() returns curl.E_READ_ERROR after readfunction return curl.READFUNC_PAUSE +-- +-- OS version : Linux Mint 17 (x86_64) +-- cURL version : libcurl/7.35.0 OpenSSL/1.0.1f zlib/1.2.8 libidn/1.28 librtmp/2.3 +-- version_info("host"): x86_64-pc-linux-gnu +-- +-- OS version : Windows XP (x86_64) +-- cURL version : libcurl/7.38.0 OpenSSL/1.0.1c zlib/1.2.7 WinIDN +-- cURL version : libcurl/7.37.1 OpenSSL/1.0.1c zlib/1.2.7 WinIDN +-- version_info("host"): i386-pc-win32 +-- +-- Works correctly on +-- (same binary as with libcurl 7.38.0/7.37.1) +-- +-- OS version : Windows XP (x86_64) +-- cURL version : libcurl/7.30.0 OpenSSL/0.9.8y zlib/1.2.7 +-- version_info("host"): i386-pc-win32 +-- + + local counter = 0 + assert_equal(c, c:setopt_readfunction(function() + if counter == 0 then + counter = counter + 1 + return curl.READFUNC_PAUSE + end + if counter == 1 then + counter = counter + 1 + return ('X'):rep(128) + end + return '' + end)) + + assert_equal(c, c:setopt_progressfunction(function() + if counter == 1 then + c:pause(curl.PAUSE_CONT) + end + end)) + + assert_equal(c, c:setopt_noprogress(false)) + + local ok, err = c:perform() + + if (not ok) and err:name() == "READ_ERROR" then + skip("TODO check pause on readfunction") + end + + assert_equal(c, ok, err) + + assert_equal(0, c:getinfo_response_code()) +end + +function test_readbuffer() + local flag = false + local N + assert_equal(c, c:setopt_readfunction(function(n) + if not flag then + flag = true + N = math.floor(n*2 + n/3) + assert(N > n) + return ("s"):rep(N) + end + return '' + end)) + + assert_equal(c, c:perform()) + c:close() + local data = read_file(fname) + assert_equal(N, #data) + assert_equal(("s"):rep(N), data) +end + +function test_pass_01() + -- We need this to support file:read() method which returns nil as EOF + assert_equal(c, c:setopt_readfunction(function() return nil end)) + + assert_equal(c, c:perform()) + c:close() + local data = read_file(fname) + assert_equal(0, #data) +end + +function test_pass_02() + local counter = 10 + assert_equal(c, c:setopt_readfunction(function() + if counter > 0 then + counter = counter - 1 + return 'a' + end + end)) + + assert_equal(c, c:perform()) + c:close() + local data = read_file(fname) + assert_equal(('a'):rep(10), data) +end + +end + +local _ENV = TEST_CASE'escape' if ENABLE then + +local c + +function teardown() + if c then c:close() end + f, c = nil +end + +function test() + local e = "This%2Bis%2Ba%2Bsimple%2B%2526%2Bshort%2Btest." + local d = "This+is+a+simple+%26+short+test." + c = assert(curl.easy()) + assert_equal(e, c:escape(d)) + assert_equal(d, c:unescape(e)) +end + +end + +local _ENV = TEST_CASE'setopt_form' if ENABLE then + +local c + +function teardown() + if c then c:close() end + c = nil +end + +function test() + local pfrom, e + do + local form = curl.form() + e = curl.easy{httppost = form} + pfrom = weak_ptr(form) + end + + gc_collect() + assert(pfrom.value) + + e:setopt_httppost(curl.form()) + + gc_collect() + assert(not pfrom.value) +end + +function test_unset() + local pfrom, e + do + local form = curl.form() + e = curl.easy{httppost = form} + pfrom = weak_ptr(form) + end + + gc_collect() + assert(pfrom.value) + + assert_equal(e, e:unsetopt_httppost()) + + gc_collect() + assert(not pfrom.value) +end + +function test_reset() + local pfrom, e + do + local form = curl.form() + e = curl.easy{httppost = form} + pform = weak_ptr(form) + end + + gc_collect() + assert(pform.value) + + assert_equal(e, e:reset()) + + gc_collect() + assert(not pform.value) +end + +end + +local _ENV = TEST_CASE'setopt_postfields' if ENABLE then + +local c + +function teardown() + if c then c:close() end + c = nil +end + +function test() + + do local fields = {} + for i = 1, 100 do fields[#fields + 1] = string.format('key%d=value%d', i, i) end + fields = table.concat(fields, '&') + c = assert(curl.easy{ + url = POST_URL, + postfields = fields, + writefunction = function()end, + }) + end + + -- call gc to try clear `fields` string + for i = 1, 4 do collectgarbage"collect" end + + c:perform() +end + +function test_unset() + local pfields + + do local fields = {} + for i = 1, 100 do fields[#fields + 1] = string.format('key%d=value%d', i, i) end + fields = table.concat(fields, '&') + c = assert(curl.easy{ + url = POST_URL, + postfields = fields, + writefunction = function()end, + }) + pfields = weak_ptr(fields) + end + + -- call gc to try clear `fields` string + for i = 1, 4 do collectgarbage"collect" end + assert_string(pfields.value) + + assert_equal(c, c:unsetopt_postfields()) + + -- @todo check internal storage because gc really do not clear `weak` string + -- for i = 1, 4 do collectgarbage"collect" end + -- assert_nil(pfields.value) + + -- c:perform() +end + +end + +local _ENV = TEST_CASE'setopt_user_data' if ENABLE then + +local c + +function teardown() + if c then c:close() end + c = nil +end + +function test_data() + c = assert(curl.easy()) + assert_nil(c:getdata()) + c:setdata("hello") + assert_equal("hello", c:getdata()) +end + +function test_cleanup() + local ptr do + local t = {} + local e = curl.easy():setdata(t) + ptr = weak_ptr(t) + gc_collect() + + assert_equal(t, ptr.value) + end + + gc_collect() + assert_nil(ptr.value) +end + +end + +local _ENV = TEST_CASE'multi_add_remove' if ENABLE then + +local m, c + +function setup() + m = assert(scurl.multi()) +end + +function teardown() + if c then c:close() end + if m then m:close() end + m, c = nil +end + +function test_remove_unknow_easy() + c = assert(scurl.easy()) + assert_equal(m, m:remove_handle(c)) +end + +function test_double_remove_easy() + c = assert(scurl.easy()) + assert_equal(m, m:add_handle(c)) + assert_equal(m, m:remove_handle(c)) + assert_equal(m, m:remove_handle(c)) +end + +function test_double_add_easy() + c = assert(scurl.easy()) + assert_equal(m, m:add_handle(c)) + assert_nil(m:add_handle(c)) +end + +end + +local _ENV = TEST_CASE'unset_callback_ctx' if ENABLE then + +local HSTS = curl.version_info().features.HSTS + +local c + +function setup() + c = assert(scurl.easy()) +end + +function teardown() + if c then c:close() end + c = nil +end + +local function test_cb(name) + local set, unset = 'setopt_' .. name, 'unsetopt_' .. name + + set = assert_function(c[set], set) + unset = assert_function(c[unset], unset) + + local pctx + do local ctx = {} + pctx = weak_ptr(ctx) + assert(set(c, function() end, ctx)) + end + + gc_collect() + assert_table(pctx.value) + + unset(c) + + gc_collect() + assert_nil(pctx.value) + + do local ctx = {} + pctx = weak_ptr(ctx) + assert(set(c, function() end, ctx)) + end + + gc_collect() + assert_table(pctx.value) + + c:reset() + + gc_collect() + assert_nil(pctx.value) +end + +function test_read() test_cb('readfunction') end +function test_write() test_cb('writefunction') end +function test_header() test_cb('headerfunction') end +function test_progress() test_cb('progressfunction') end +function test_seek() test_cb('seekfunction') end +function test_debug() test_cb('debugfunction') end +function test_fnmatch() test_cb('fnmatch_function') end +function test_chunk_bgn() test_cb('chunk_bgn_function') end +function test_chunk_end() test_cb('chunk_end_function') end + +if curl.OPT_HSTSREADFUNCTION and HSTS then +function test_hstsreadfunction() test_cb('hstsreadfunction') end +function test_hstswritefunction() test_cb('hstswritefunction') end +end + +end + +local _ENV = TEST_CASE'set_slist' if ENABLE then + +local c + +function teardown() + if c then c:close() end + c = nil +end + +function test_set() + c = curl.easy() + c:setopt_httpheader({'X-Custom: value'}) + local body, headers = assert_string(dump_request(c)) + assert_match("X%-Custom:%s*value\r\n", headers) +end + +function test_unset() + c = curl.easy() + c:setopt_httpheader({'X-Custom: value'}) + c:unsetopt_httpheader() + local body, headers = assert_string(dump_request(c)) + assert_not_match("X%-Custom:%s*value\r\n", headers) +end + +function test_set_empty_array() + c = curl.easy() + c:setopt_httpheader({'X-Custom: value'}) + c:setopt_httpheader({}) + local body, headers = assert_string(dump_request(c)) + assert_not_match("X%-Custom:%s*value\r\n", headers) +end + +function test_reset_slist() + c = curl.easy { + httpheader = {'X-Foo: 1'}, + resolve = {'example.com:80:127.0.0.1'} + } + + c:reset() + + c:setopt{ + httpheader = {'X-Foo: 2'}, + resolve = {'example.com:80:127.0.0.1'} + } + + local body, headers = assert_string(dump_request(c)) + assert_match("X%-Foo:%s2\r\n", headers) +end + +end + +local _ENV = TEST_CASE'set_null' if ENABLE then + +local c, m + +function teardown() + if c then c:close() end + if m then m:close() end + m, c = nil +end + +function test_string() + c = curl.easy() + c:setopt_accept_encoding('gzip') + local body, headers = assert_string(dump_request(c)) + assert_match("Accept%-Encoding:%s*gzip", headers) + + c:setopt_accept_encoding(null) + body, headers = assert_string(dump_request(c)) + assert_not_match("Accept%-Encoding:%s*gzip", headers) +end + +function test_string_via_table() + c = curl.easy() + c:setopt_accept_encoding('gzip') + local body, headers = assert_string(dump_request(c)) + assert_match("Accept%-Encoding:%s*gzip", headers) + + c:setopt{ accept_encoding = null } + body, headers = assert_string(dump_request(c)) + assert_not_match("Accept%-Encoding:%s*gzip", headers) +end + +function test_slist() + c = curl.easy() + c:setopt_httpheader({'X-Custom: value'}) + c:setopt_httpheader(null) + local body, headers = assert_string(dump_request(c)) + assert_not_match("X%-Custom:%s*value\r\n", headers) +end + +function test_slist_via_table() + c = curl.easy() + c:setopt_httpheader({'X-Custom: value'}) + c:setopt{httpheader = null} + local body, headers = assert_string(dump_request(c)) + assert_not_match("X%-Custom:%s*value\r\n", headers) +end + +function test_multi_set_array() + m = curl.multi() + m:setopt_pipelining_site_bl{ + '127.0.0.1' + } + assert_equal(m, m:setopt_pipelining_site_bl(null)) +end + +end + +local _ENV = TEST_CASE'trailer_callback' if ENABLE and is_curl_ge(7,64,0) then + +local url = POST_URL + +local m, c, t + +local function json_data() + return json.decode(table.concat(t)) +end + +local treader = function(t) + local i = 0 + return function() + i = i + 1 + return t[i] + end +end + +function setup() + t = {} + c = assert(scurl.easy{ + url = url, + post = true, + httpheader = {"Transfer-Encoding: chunked"}, + readfunction = treader {'a=1&', 'b=2&'}, + timeout = 60, + }) + assert_equal(c, c:setopt_writefunction(table.insert, t)) +end + +function teardown() + if c then c:close() end + if m then m:close() end + t, c, m = nil +end + +local empty_responses = { + {'no_response', function() end}, + {'nil_response', function() return nil end}, + {'null_response', function() return curl.null end}, + {'true_response', function() return true end}, + {'empty_array', function() return {} end}, +} + +local abort_responses = { + {'false_response', function() return false end}, + {'nil_with_error_response', function() return nil, 'error message' end}, + {'numeric_response_0', function() return 0 end}, + {'numeric_response_1', function() return 1 end}, +} + +for _, response in ipairs(empty_responses) do + _ENV[ 'test_' .. response[1] ] = function() + local trailer_called = 0 + assert_equal(c, c:setopt_trailerfunction(function() + trailer_called = trailer_called + 1 + return response[2]() + end)) + + assert_equal(c, c:perform()) + + assert_equal(1, trailer_called) + + assert_equal(200, c:getinfo_response_code()) + local data = assert_table(json_data()) + + assert_equal('1', data.form.a) + assert_equal('2', data.form.b) + end +end + +for _, response in ipairs(abort_responses) do + _ENV[ 'test_' .. response[1] ] = function() + local trailer_called = 0 + assert_equal(c, c:setopt_trailerfunction(function() + trailer_called = trailer_called + 1 + return response[2]() + end)) + + local ok, err = assert_nil(c:perform()) + assert_equal(1, trailer_called) + assert_equal(curl.error(curl.ERROR_EASY, curl.E_ABORTED_BY_CALLBACK), err) + end +end + +function test_send_header() + local trailer_called = 0 + assert_equal(c, c:setopt_trailerfunction(function() + trailer_called = trailer_called + 1 + return {'x-trailer-header: value'} + end)) + + assert_equal(c, c:perform()) + + assert_equal(1, trailer_called) + + assert_equal(200, c:getinfo_response_code()) + local data = assert_table(json_data()) + + assert_equal('1', data.form.a) + assert_equal('2', data.form.b) + assert_equal('value', data.headers['x-trailer-header']) +end + +end + +RUN()