Init commit

This commit is contained in:
Alexey Melnichuk 2014-08-25 13:12:45 +05:00
parent 5458154562
commit b46fc0ad25
18 changed files with 2421 additions and 0 deletions

60
README.md Normal file
View File

@ -0,0 +1,60 @@
# Lua binding to [libcurl](http://curl.haxx.se/libcurl)
## Usage
```Lua
-- HTTP Get
curl:easy()
:setopt_url('http://httpbin.org/get')
:setopt_httpheader{
"X-Test-Header1: Header-Data1",
"X-Test-Header2: Header-Data2",
}
:setopt_writefunction(io.stderr)
:perform()
:close()
```
```Lua
-- HTTP Post
curl:easy()
:setopt_url('http://posttestserver.com/post.php')
:setopt_writefunction(io.write)
:setopt_httppost(curl.httppost()
:add_content("test_content", "some data", {
"MyHeader: SomeValue"
})
:add_buffer("test_file", "filename", "text data", "text/plain", {
"Description: my file description"
})
:add_file("test_file2", "BuildLog.htm", "application/octet-stream", {
"Description: my file description"
})
)
:perform()
:close()
```
```Lua
-- FTP Upload
local function get_bin_by(str,n)
local pos = 1 - n
return function()
pos = pos + n
return (str:sub(pos,pos+n-1))
end
end
curl:easy()
:setopt_url("ftp://moteus:123456@127.0.0.1/test.dat")
:setopt_upload(true)
:setopt_readfunction(
get_bin_by(("0123456789"):rep(4), 9)
)
:perform()
:close()
```

145
doc/lcurl.ldoc Normal file
View File

@ -0,0 +1,145 @@
---
-- @module lcurl
--- Create HTTP multipart object.
--
-- @treturn[1] httppost new curl HTTP Post object context
function httppost() end
--- HTTP multipart/formdata object
-- @type httppost
--
do
--- Add new part to form.
--
-- @tparam string name provide the name of this part
-- @tparam string content actual data to send
-- @tparam[opt] string type provides the content-type for this part
-- @tparam[opt] table headers specifies extra headers for the form POST section
-- @return[1] self
function httppost:add_content() end
--- Add new part to form.
--
-- @tparam string name provide the name of this part
-- @tparam string filename provides the filename field in the content header
-- @tparam string content actual data to send
-- @tparam[opt] string type provides the content-type for this part
-- @tparam[opt] table headers specifies extra headers for the form POST section
-- @return[1] self
function httppost:add_buffer() end
--- Add new part to form.
--
-- @tparam string name provide the name of this part
-- @tparam string path path to file that contain actual data to send
-- @tparam[opt] string type provides the content-type for this part
-- @tparam[opt] string filename provides the filename field in the content header.
-- By default it is basename of path.
-- @tparam[opt] table headers specifies extra headers for the form POST section
-- @return[1] self
function httppost:add_file() end
--- Serialize multipart/formdata HTTP POST chain.
--
-- @return[1] string serialized data
--
-- @usage print(post:get())
--
function httppost:get() end
--- Serialize multipart/formdata HTTP POST chain.
--
-- Writer function can return true or number of written bytes.
-- Also if function does not return anything is considered as success.
--
-- @tparam function writer
-- @param[opt] context writer context
-- @return[1] self
--
-- @usage
-- t = {}
-- post:get(table.insert, t)
-- print(table.concat(t))
--
function httppost:get() end
--- Serialize multipart/formdata HTTP POST chain.
--
-- This call same as httppost:get(writer.write, writer)
--
-- @tparam object writer
-- @return[1] self
--
-- @usage
-- f = io.open(...)
-- post:get(f)
--
function httppost:get() end
--- Free multipart/formdata.
--
function httppost:free() end
end
--- Easy curl object
-- @type easy
--
do
--- Set writer function.
--
-- @tparam function writer
-- @param[opt] context writer context
-- @return[1] self
--
function easy:setopt_writefunction() end
--- Set writer function.
--
-- This call same as easy:set_writefunction(writer.write, writer)
--
-- @tparam object writer
-- @return[1] self
--
function easy:setopt_writefunction() end
--- Set reader function.
--
-- @tparam function reader
-- @param[opt] context reader context
-- @return[1] self
--
function easy:setopt_readfunction() end
--- Set reader function.
--
-- This call same as easy:set_readfunction(reader.read, reader)
--
-- @tparam object reader
-- @return[1] self
--
function easy:setopt_readfunction() end
--- Set HTTP multipart/formdata
--
-- @tparam httppost data
-- @return[1] self
function easy:setopt_httppost() end
--- Set HTTP multipart/formdata
--
-- @tparam string data
-- @tparam[opt=#data] number length
-- @return[1] self
function easy:setopt_postfields() end
--- End easy session
--
function easy:close() end
end

20
msvc/lcurl.sln Normal file
View File

@ -0,0 +1,20 @@

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lcurl", "lcurl.vcproj", "{200D5C0C-8123-48F6-9EA0-CF0E6A6943F2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{200D5C0C-8123-48F6-9EA0-CF0E6A6943F2}.Debug|Win32.ActiveCfg = Debug|Win32
{200D5C0C-8123-48F6-9EA0-CF0E6A6943F2}.Debug|Win32.Build.0 = Debug|Win32
{200D5C0C-8123-48F6-9EA0-CF0E6A6943F2}.Release|Win32.ActiveCfg = Release|Win32
{200D5C0C-8123-48F6-9EA0-CF0E6A6943F2}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

240
msvc/lcurl.vcproj Normal file
View File

@ -0,0 +1,240 @@
<?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="lcurl"
ProjectGUID="{200D5C0C-8123-48F6-9EA0-CF0E6A6943F2}"
RootNamespace="lcurl"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="2"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="$(CPPLIB_DIR)\curl\7.37.1\include;$(LUA_DIR)\include"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LCURL_EXPORTS"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="lua5.1.lib libcurl.lib"
LinkIncremental="2"
AdditionalLibraryDirectories="&quot;$(CPPLIB_DIR)\curl\7.37.1\lib&quot;;&quot;$(LUA_DIR)\lib&quot;"
GenerateDebugInformation="true"
SubSystem="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="2"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LCURL_EXPORTS"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="..\src\l52util.c"
>
</File>
<File
RelativePath="..\src\lceasy.c"
>
</File>
<File
RelativePath="..\src\lcerror.c"
>
</File>
<File
RelativePath="..\src\lchttppost.c"
>
</File>
<File
RelativePath="..\src\lcurl.c"
>
</File>
<File
RelativePath="..\src\lcutils.c"
>
</File>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath="..\src\l52util.h"
>
</File>
<File
RelativePath="..\src\lceasy.h"
>
</File>
<File
RelativePath="..\src\lcerror.h"
>
</File>
<File
RelativePath="..\src\lchttppost.h"
>
</File>
<File
RelativePath="..\src\lcurl.h"
>
</File>
<File
RelativePath="..\src\lcutils.h"
>
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

147
src/l52util.c Normal file
View File

@ -0,0 +1,147 @@
#include "l52util.h"
#include <memory.h>
#include <assert.h>
#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);
}
int luaL_getmetafield (lua_State *L, int obj, const char *event) {
if (!lua_getmetatable(L, obj)) /* no metatable? */
return 0;
lua_pushstring(L, event);
lua_rawget(L, -2);
if (lua_isnil(L, -1)) {
lua_pop(L, 2); /* remove metatable and metafield */
return 0;
}
else {
lua_remove(L, -2); /* remove only metatable */
return 1;
}
}
int luaL_callmeta (lua_State *L, int obj, const char *event) {
obj = lua_absindex(L, obj);
if (!luaL_getmetafield(L, obj, event)) /* no metafield? */
return 0;
lua_pushvalue(L, obj);
lua_call(L, 1, 1);
return 1;
}
#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_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;
}

55
src/l52util.h Normal file
View File

@ -0,0 +1,55 @@
#ifndef _L52UTIL_H_
#define _L52UTIL_H_
#include "lua.h"
#include "lauxlib.h"
#if LUA_VERSION_NUM >= 502 // lua 5.2
// lua_rawgetp
// lua_rawsetp
// luaL_setfuncs
// lua_absindex
#ifndef lua_objlen
#define lua_objlen lua_rawlen
#endif
int luaL_typerror (lua_State *L, int narg, const char *tname);
#ifndef luaL_register
void luaL_register (lua_State *L, const char *libname, const luaL_Reg *l);
#endif
#else // lua 5.1
// functions form lua 5.2
# define lua_absindex(L, i) (((i)>0)?(i):((i)<=LUA_REGISTRYINDEX?(i):(lua_gettop(L)+(i)+1)))
# define lua_rawlen lua_objlen
void lua_rawgetp (lua_State *L, int index, const void *p);
void lua_rawsetp (lua_State *L, int index, const void *p);
void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup);
int luaL_getmetafield (lua_State *L, int obj, const char *event);
int luaL_callmeta (lua_State *L, int obj, const char *event);
#endif
int lutil_newmetatablep (lua_State *L, const void *p);
void lutil_getmetatablep (lua_State *L, const void *p);
void lutil_setmetatablep (lua_State *L, const void *p);
#define lutil_newudatap(L, TTYPE, TNAME) (TTYPE *)lutil_newudatap_impl(L, sizeof(TTYPE), TNAME)
int lutil_isudatap (lua_State *L, int ud, const void *p);
void *lutil_checkudatap (lua_State *L, int ud, const void *p);
int lutil_createmetap (lua_State *L, const void *p, const luaL_Reg *methods, int nup);
void *lutil_newudatap_impl (lua_State *L, size_t size, const void *p);
#endif

569
src/lceasy.c Normal file
View File

@ -0,0 +1,569 @@
#include "lcurl.h"
#include "lceasy.h"
#include "lcerror.h"
#include "lcutils.h"
#include "lchttppost.h"
#define LCURL_EASY_NAME LCURL_PREFIX" Easy"
static const char *LCURL_EASY = LCURL_EASY_NAME;
typedef struct lcurl_callback_tag{
int cb_ref;
int ud_ref;
}lcurl_callback_t;
typedef struct lcurl_read_buffer_tag{
int ref;
int off;
}lcurl_read_buffer_t;
#define LCURL_LST_INDEX(N) LCURL_##N##_LIST,
#define LCURL_STR_INDEX(N)
#define LCURL_LNG_INDEX(N)
#define OPT_ENTRY(L, N, T, S) LCURL_##T##_INDEX(N)
enum {
LCURL_LISY_DUMMY = -1,
#include"lcopteasy.h"
LCURL_LIST_COUNT,
};
#undef LCURL_LST_INDEX
#undef LCURL_STR_INDEX
#undef LCURL_LNG_INDEX
#undef OPT_ENTRY
typedef struct lcurl_easy_tag{
lua_State *L;
CURL *curl;
int storage;
int lists[LCURL_LIST_COUNT];
int err_mode;
lcurl_callback_t wr;
lcurl_callback_t rd;
lcurl_read_buffer_t rbuffer;
}lcurl_easy_t;
//{
int lcurl_easy_create(lua_State *L, int error_mode){
lcurl_easy_t *p = lutil_newudatap(L, lcurl_easy_t, LCURL_EASY);
int i;
p->L = L;
p->curl = curl_easy_init();
if(!p->curl) return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, CURLE_FAILED_INIT);
p->storage = lcurl_storage_init(L);
p->err_mode = error_mode;
p->wr.cb_ref = p->wr.ud_ref = LUA_NOREF;
p->rd.cb_ref = p->rd.ud_ref = LUA_NOREF;
p->rbuffer.ref = LUA_NOREF;
for(i = 0; i < LCURL_LIST_COUNT; ++i){
p->lists[i] = LUA_NOREF;
}
return 1;
}
static lcurl_easy_t *lcurl_geteasy_at(lua_State *L, int i){
lcurl_easy_t *p = (lcurl_easy_t *)lutil_checkudatap (L, i, LCURL_EASY);
luaL_argcheck (L, p != NULL, 1, LCURL_PREFIX"HTTPPost object expected");
return p;
}
#define lcurl_geteasy(L) lcurl_geteasy_at((L),1)
static int lcurl_easy_cleanup(lua_State *L){
lcurl_easy_t *p = lcurl_geteasy(L);
if(p->curl){
curl_easy_cleanup(p->curl);
p->curl = NULL;
}
if(p->storage != LUA_NOREF){
lcurl_storage_free(L, p->storage);
p->storage = LUA_NOREF;
}
return 0;
}
static int lcurl_easy_perform(lua_State *L){
lcurl_easy_t *p = lcurl_geteasy(L);
CURLcode code;
lua_settop(L, 1);
assert(p->rbuffer.ref == LUA_NOREF);
code = curl_easy_perform(p->curl);
if(p->rbuffer.ref != LUA_NOREF){
luaL_unref(L, LCURL_LUA_REGISTRY, p->rbuffer.ref);
p->rbuffer.ref = LUA_NOREF;
}
if(code == CURLE_OK){
lua_settop(L, 1);
return 1;
}
if(code == CURLE_WRITE_ERROR){
/* error from callback*/
if(lua_gettop(L) > 1){
if(lua_isstring(L, 2)) return lua_error(L);
return lua_gettop(L) - 1;
}
}
if(code == CURLE_ABORTED_BY_CALLBACK){
if(lua_gettop(L) > 1){
if(lua_isstring(L, 2)) return lua_error(L);
return lua_gettop(L) - 1;
}
}
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code);
}
//{ OPTIONS
static int lcurl_opt_set_long_(lua_State *L, int opt){
lcurl_easy_t *p = lcurl_geteasy(L);
long val; CURLcode code;
if(lua_isboolean(L, 2)) val = lua_toboolean(L, 2);
else val = luaL_checklong(L, 2);
code = curl_easy_setopt(p->curl, opt, val);
if(code != CURLE_OK){
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code);
}
lua_settop(L, 1);
return 1;
}
static int lcurl_opt_set_string_(lua_State *L, int opt, int store){
lcurl_easy_t *p = lcurl_geteasy(L);
const char *val = luaL_checkstring(L, 2);
CURLcode code = curl_easy_setopt(p->curl, opt, val);
if(code != CURLE_OK){
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code);
}
if(store)lcurl_storage_preserve_value(L, p->storage, 2);
lua_settop(L, 1);
return 1;
}
static int lcurl_opt_set_slist_(lua_State *L, int opt, int list_no){
lcurl_easy_t *p = lcurl_geteasy(L);
struct curl_slist *list = lcurl_util_to_slist(L, 2);
CURLcode code;
int ref = p->lists[list_no];
luaL_argcheck(L, list, 2, "array expected");
if(ref != LUA_NOREF){
struct curl_slist *tmp = lcurl_storage_remove_slist(L, p->storage, ref);
curl_slist_free_all(tmp);
p->lists[list_no] = LUA_NOREF;
}
code = curl_easy_setopt(p->curl, opt, list);
if(code != CURLE_OK){
curl_slist_free_all(list);
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code);
}
p->lists[list_no] = lcurl_storage_preserve_slist(L, p->storage, list);
lua_settop(L, 1);
return 1;
}
#define LCURL_STR_OPT(N, S) static int lcurl_easy_set_##N(lua_State *L){\
return lcurl_opt_set_string_(L, CURLOPT_##N, (S)); \
}
#define LCURL_LST_OPT(N, S) static int lcurl_easy_set_##N(lua_State *L){\
return lcurl_opt_set_slist_(L, CURLOPT_##N, LCURL_##N##_LIST);\
}
#define LCURL_LNG_OPT(N, S) static int lcurl_easy_set_##N(lua_State *L){\
return lcurl_opt_set_long_(L, CURLOPT_##N);\
}
#define OPT_ENTRY(L, N, T, S) LCURL_##T##_OPT(N, S)
#include "lcopteasy.h"
#undef OPT_ENTRY
static int lcurl_easy_set_POSTFIELDS(lua_State *L){
lcurl_easy_t *p = lcurl_geteasy(L);
size_t len; const char *val = luaL_checklstring(L, 2, &len);
CURLcode code;
if(lua_isnumber(L, 3)){
size_t n = (size_t)lua_tonumber(L, 3);
luaL_argcheck(L, len <= n, 3, "data length too big");
len = n;
}
code = curl_easy_setopt(p->curl, CURLOPT_POSTFIELDS, val);
if(code != CURLE_OK){
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code);
}
lcurl_storage_preserve_value(L, p->storage, 2);
code = curl_easy_setopt(p->curl, CURLOPT_POSTFIELDSIZE, (long)len);
if(code != CURLE_OK){
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code);
}
lua_settop(L, 1);
return 1;
}
#undef LCURL_STR_OPT
#undef LCURL_LST_OPT
#undef LCURL_LNG_OPT
static int lcurl_easy_set_HTTPPOST(lua_State *L){
lcurl_easy_t *p = lcurl_geteasy(L);
lcurl_hpost_t *post = lcurl_gethpost_at(L, 2);
CURLcode code = curl_easy_setopt(p->curl, CURLOPT_HTTPPOST, post->post);
if(code != CURLE_OK){
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code);
}
lcurl_storage_preserve_value(L, p->storage, 2);
lua_settop(L, 1);
return 1;
}
//}
//{ info
static int lcurl_info_get_long_(lua_State *L, int opt){
lcurl_easy_t *p = lcurl_geteasy(L);
long val; CURLcode code;
code = curl_easy_getinfo(p->curl, opt, &val);
if(code != CURLE_OK){
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code);
}
lua_pushnumber(L, val);
return 1;
}
static int lcurl_info_get_double_(lua_State *L, int opt){
lcurl_easy_t *p = lcurl_geteasy(L);
double val; CURLcode code;
code = curl_easy_getinfo(p->curl, opt, &val);
if(code != CURLE_OK){
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code);
}
lua_pushnumber(L, val);
return 1;
}
static int lcurl_info_get_string_(lua_State *L, int opt){
lcurl_easy_t *p = lcurl_geteasy(L);
char *val; CURLcode code;
code = curl_easy_getinfo(p->curl, opt, &val);
if(code != CURLE_OK){
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code);
}
lua_pushstring(L, val);
return 1;
}
static int lcurl_info_get_slist_(lua_State *L, int opt){
lcurl_easy_t *p = lcurl_geteasy(L);
struct curl_slist *val; CURLcode code;
code = curl_easy_getinfo(p->curl, opt, &val);
if(code != CURLE_OK){
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code);
}
lcurl_util_slist_to_table(L, val);
curl_slist_free_all(val);
return 1;
}
#define LCURL_STR_INFO(N, S) static int lcurl_easy_get_##N(lua_State *L){\
return lcurl_info_get_string_(L, CURLINFO_##N); \
}
#define LCURL_LST_INFO(N, S) static int lcurl_easy_get_##N(lua_State *L){\
return lcurl_info_get_slist_(L, CURLINFO_##N);\
}
#define LCURL_LNG_INFO(N, S) static int lcurl_easy_get_##N(lua_State *L){\
return lcurl_info_get_long_(L, CURLINFO_##N);\
}
#define LCURL_DBL_INFO(N, S) static int lcurl_easy_get_##N(lua_State *L){\
return lcurl_info_get_double_(L, CURLINFO_##N);\
}
#define OPT_ENTRY(L, N, T, S) LCURL_##T##_INFO(N, S)
#include "lcinfoeasy.h"
#undef OPT_ENTRY
#undef LCURL_STR_INFO
#undef LCURL_LST_INFO
#undef LCURL_LNG_INFO
#undef LCURL_DBL_INFO
//}
//{ CallBack
static int lcurl_util_push_cb(lua_State *L, lcurl_callback_t *c){
assert(c->cb_ref != LUA_NOREF);
lua_rawgeti(L, LCURL_LUA_REGISTRY, c->cb_ref);
if(c->ud_ref != LUA_NOREF){
lua_rawgeti(L, LCURL_LUA_REGISTRY, c->ud_ref);
return 2;
}
return 1;
}
//{ Writer
static int lcurl_write_callback(char *ptr, size_t size, size_t nmemb, void *arg){
lcurl_easy_t *p = arg;
lua_State *L = p->L;
size_t ret = size * nmemb;
int top = lua_gettop(L);
int n = lcurl_util_push_cb(L, &p->wr);
lua_pushlstring(L, ptr, ret);
if(lua_pcall(L, n, LUA_MULTRET, 0)) return 0;
if(lua_gettop(L) > top){
if(lua_isnil(L, top + 1)) return 0;
if(lua_isboolean(L, top + 1)){
if(!lua_toboolean(L, top + 1)) ret = 0;
}
else ret = (size_t)lua_tonumber(L, top + 1);
}
lua_settop(L, top);
return ret;
}
static int lcurl_easy_set_WRITEFUNCTION(lua_State *L){
lcurl_easy_t *p = lcurl_geteasy(L);
lcurl_callback_t *c = &p->wr;
if(c->ud_ref != LUA_NOREF){
luaL_unref(L, LCURL_LUA_REGISTRY, c->ud_ref);
c->ud_ref = LUA_NOREF;
}
if(c->cb_ref != LUA_NOREF){
luaL_unref(L, LCURL_LUA_REGISTRY, c->cb_ref);
c->cb_ref = LUA_NOREF;
}
if(lua_gettop(L) >= 3){// writer + context
lua_settop(L, 3);
luaL_argcheck(L, !lua_isnil(L, 2), 2, "no writer present");
c->ud_ref = luaL_ref(L, LCURL_LUA_REGISTRY);
c->cb_ref = luaL_ref(L, LCURL_LUA_REGISTRY);
assert(1 == lua_gettop(L));
return 1;
}
lua_settop(L, 2);
if(lua_isnoneornil(L, 2)){
lua_pop(L, 1);
assert(1 == lua_gettop(L));
curl_easy_setopt(p->curl, CURLOPT_WRITEDATA, 0);
curl_easy_setopt(p->curl, CURLOPT_WRITEFUNCTION, 0);
return 1;
}
curl_easy_setopt(p->curl, CURLOPT_WRITEDATA, p);
curl_easy_setopt(p->curl, CURLOPT_WRITEFUNCTION, lcurl_write_callback);
if(lua_isfunction(L, 2)){
c->cb_ref = luaL_ref(L, LCURL_LUA_REGISTRY);
assert(1 == lua_gettop(L));
return 1;
}
if(lua_isuserdata(L, 2) || lua_istable(L, 2)){
lua_getfield(L, 2, "write");
luaL_argcheck(L, lua_isfunction(L, -1), 2, "write method not found in object");
c->cb_ref = luaL_ref(L, LCURL_LUA_REGISTRY);
c->ud_ref = luaL_ref(L, LCURL_LUA_REGISTRY);
assert(1 == lua_gettop(L));
return 1;
}
lua_pushliteral(L, "invalid writer type");
return lua_error(L);
}
//}
//{ Reader
static int lcurl_read_callback(char *buffer, size_t size, size_t nitems, void *arg){
lcurl_easy_t *p = arg;
lua_State *L = p->L;
const char *data; size_t data_size;
size_t ret = size * nitems;
int n, top = lua_gettop(L);
if(p->rbuffer.ref != LUA_NOREF){
lua_rawgeti(L, LCURL_LUA_REGISTRY, p->rbuffer.ref);
data = luaL_checklstring(L, -1, &data_size);
lua_pop(L, 1);
data = data + p->rbuffer.off;
data_size -= p->rbuffer.off;
if(data_size > ret){
data_size = ret;
memcpy(buffer, data, data_size);
p->rbuffer.off += data_size;
}
else{
memcpy(buffer, data, data_size);
luaL_unref(L, LCURL_LUA_REGISTRY, p->rbuffer.ref);
p->rbuffer.ref = LUA_NOREF;
}
lua_settop(L, top);
return data_size;
}
// buffer is clean
assert(p->rbuffer.ref == LUA_NOREF);
n = lcurl_util_push_cb(L, &p->rd);
lua_pushnumber(L, ret);
if(lua_pcall(L, n, LUA_MULTRET, 0)) return CURL_READFUNC_ABORT;
if(lua_isnoneornil(L, top + 1)) return CURL_READFUNC_ABORT;
data = lua_tolstring(L, -1, &data_size);
if(!data) return CURL_READFUNC_ABORT;
if(data_size > ret){
data_size = ret;
p->rbuffer.ref = luaL_ref(L, LCURL_LUA_REGISTRY);
p->rbuffer.off = data_size;
}
memcpy(buffer, data, data_size);
lua_settop(L, top);
return data_size;
}
static int lcurl_easy_set_READFUNCTION(lua_State *L){
lcurl_easy_t *p = lcurl_geteasy(L);
lcurl_callback_t *c = &p->rd;
if(c->ud_ref != LUA_NOREF){
luaL_unref(L, LCURL_LUA_REGISTRY, c->ud_ref);
c->ud_ref = LUA_NOREF;
}
if(c->cb_ref != LUA_NOREF){
luaL_unref(L, LCURL_LUA_REGISTRY, c->cb_ref);
c->cb_ref = LUA_NOREF;
}
if(lua_gettop(L) >= 3){// writer + context
lua_settop(L, 3);
luaL_argcheck(L, !lua_isnil(L, 2), 2, "no writer present");
c->ud_ref = luaL_ref(L, LCURL_LUA_REGISTRY);
c->cb_ref = luaL_ref(L, LCURL_LUA_REGISTRY);
assert(1 == lua_gettop(L));
return 1;
}
lua_settop(L, 2);
if(lua_isnoneornil(L, 2)){
lua_pop(L, 1);
assert(1 == lua_gettop(L));
curl_easy_setopt(p->curl, CURLOPT_READDATA, 0);
curl_easy_setopt(p->curl, CURLOPT_READFUNCTION, 0);
return 1;
}
curl_easy_setopt(p->curl, CURLOPT_READDATA, p);
curl_easy_setopt(p->curl, CURLOPT_READFUNCTION, lcurl_read_callback);
if(lua_isfunction(L, 2)){
c->cb_ref = luaL_ref(L, LCURL_LUA_REGISTRY);
assert(1 == lua_gettop(L));
return 1;
}
if(lua_isuserdata(L, 2) || lua_istable(L, 2)){
lua_getfield(L, 2, "read");
luaL_argcheck(L, lua_isfunction(L, -1), 2, "read method not found in object");
c->cb_ref = luaL_ref(L, LCURL_LUA_REGISTRY);
c->ud_ref = luaL_ref(L, LCURL_LUA_REGISTRY);
assert(1 == lua_gettop(L));
return 1;
}
lua_pushliteral(L, "invalid reader type");
return lua_error(L);
}
//}
//}
//}
#define OPT_ENTRY(L, N, T, S) { "setopt_"#L, lcurl_easy_set_##N },
static const struct luaL_Reg lcurl_easy_methods[] = {
#include "lcopteasy.h"
OPT_ENTRY(httppost, HTTPPOST, TTT, 0)
OPT_ENTRY(writefunction, WRITEFUNCTION, TTT, 0)
OPT_ENTRY(readfunction, READFUNCTION, TTT, 0)
{"getinfo_effective_url", lcurl_easy_get_EFFECTIVE_URL },
{"perform", lcurl_easy_perform },
{"close", lcurl_easy_cleanup },
{"__gc", lcurl_easy_cleanup },
{NULL,NULL}
};
#undef OPT_ENTRY
void lcurl_easy_initlib(lua_State *L, int nup){
if(!lutil_createmetap(L, LCURL_EASY, lcurl_easy_methods, nup))
lua_pop(L, nup);
lua_pop(L, 1);
}

10
src/lceasy.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef _LCEASY_H_
#define _LCEASY_H_
#include "lcurl.h"
int lcurl_easy_create(lua_State *L, int error_mode);
void lcurl_easy_initlib(lua_State *L, int nup);
#endif

320
src/lcerror.c Normal file
View File

@ -0,0 +1,320 @@
/*
Author: Alexey Melnichuk <mimir@newmail.ru>
Copyright (C) 2013-2014 Alexey Melnichuk <mimir@newmail.ru>
Licensed according to the included 'LICENCE' document
This file is part of lua-lcurl library.
*/
#include "lcurl.h"
#include "lcerror.h"
#include <assert.h>
#define LCURL_ERROR_NAME LCURL_PREFIX" Error"
static const char *LCURL_ERROR = LCURL_ERROR_NAME;
typedef struct lcurl_error_tag{
int tp;
int no;
}lcurl_error_t;
//{
static const char* lcurl_err_easy_mnemo(int err){
#define RETURN_IF(E) case CURLE_##E: return #E;
switch (err){
RETURN_IF ( OK )
RETURN_IF ( UNSUPPORTED_PROTOCOL )
RETURN_IF ( FAILED_INIT )
RETURN_IF ( URL_MALFORMAT )
RETURN_IF ( NOT_BUILT_IN )
RETURN_IF ( COULDNT_RESOLVE_PROXY )
RETURN_IF ( COULDNT_RESOLVE_HOST )
RETURN_IF ( COULDNT_CONNECT )
RETURN_IF ( FTP_WEIRD_SERVER_REPLY )
RETURN_IF ( REMOTE_ACCESS_DENIED )
RETURN_IF ( FTP_ACCEPT_FAILED )
RETURN_IF ( FTP_WEIRD_PASS_REPLY )
RETURN_IF ( FTP_ACCEPT_TIMEOUT )
RETURN_IF ( FTP_WEIRD_PASV_REPLY )
RETURN_IF ( FTP_WEIRD_227_FORMAT )
RETURN_IF ( FTP_CANT_GET_HOST )
RETURN_IF ( OBSOLETE16 )
RETURN_IF ( FTP_COULDNT_SET_TYPE )
RETURN_IF ( PARTIAL_FILE )
RETURN_IF ( FTP_COULDNT_RETR_FILE )
RETURN_IF ( OBSOLETE20 )
RETURN_IF ( QUOTE_ERROR )
RETURN_IF ( HTTP_RETURNED_ERROR )
RETURN_IF ( WRITE_ERROR )
RETURN_IF ( OBSOLETE24 )
RETURN_IF ( UPLOAD_FAILED )
RETURN_IF ( READ_ERROR )
RETURN_IF ( OUT_OF_MEMORY )
RETURN_IF ( OPERATION_TIMEDOUT )
RETURN_IF ( OBSOLETE29 )
RETURN_IF ( FTP_PORT_FAILED )
RETURN_IF ( FTP_COULDNT_USE_REST )
RETURN_IF ( OBSOLETE32 )
RETURN_IF ( RANGE_ERROR )
RETURN_IF ( HTTP_POST_ERROR )
RETURN_IF ( SSL_CONNECT_ERROR )
RETURN_IF ( BAD_DOWNLOAD_RESUME )
RETURN_IF ( FILE_COULDNT_READ_FILE )
RETURN_IF ( LDAP_CANNOT_BIND )
RETURN_IF ( LDAP_SEARCH_FAILED )
RETURN_IF ( OBSOLETE40 )
RETURN_IF ( FUNCTION_NOT_FOUND )
RETURN_IF ( ABORTED_BY_CALLBACK )
RETURN_IF ( BAD_FUNCTION_ARGUMENT )
RETURN_IF ( OBSOLETE44 )
RETURN_IF ( INTERFACE_FAILED )
RETURN_IF ( OBSOLETE46 )
RETURN_IF ( TOO_MANY_REDIRECTS )
RETURN_IF ( UNKNOWN_OPTION )
RETURN_IF ( TELNET_OPTION_SYNTAX )
RETURN_IF ( OBSOLETE50 )
RETURN_IF ( PEER_FAILED_VERIFICATION )
RETURN_IF ( GOT_NOTHING )
RETURN_IF ( SSL_ENGINE_NOTFOUND )
RETURN_IF ( SSL_ENGINE_SETFAILED )
RETURN_IF ( SEND_ERROR )
RETURN_IF ( RECV_ERROR )
RETURN_IF ( OBSOLETE57 )
RETURN_IF ( SSL_CERTPROBLEM )
RETURN_IF ( SSL_CIPHER )
RETURN_IF ( SSL_CACERT )
RETURN_IF ( BAD_CONTENT_ENCODING )
RETURN_IF ( LDAP_INVALID_URL )
RETURN_IF ( FILESIZE_EXCEEDED )
RETURN_IF ( USE_SSL_FAILED )
RETURN_IF ( SEND_FAIL_REWIND )
RETURN_IF ( SSL_ENGINE_INITFAILED )
RETURN_IF ( LOGIN_DENIED )
RETURN_IF ( TFTP_NOTFOUND )
RETURN_IF ( TFTP_PERM )
RETURN_IF ( REMOTE_DISK_FULL )
RETURN_IF ( TFTP_ILLEGAL )
RETURN_IF ( TFTP_UNKNOWNID )
RETURN_IF ( REMOTE_FILE_EXISTS )
RETURN_IF ( TFTP_NOSUCHUSER )
RETURN_IF ( CONV_FAILED )
RETURN_IF ( CONV_REQD )
RETURN_IF ( SSL_CACERT_BADFILE )
RETURN_IF ( REMOTE_FILE_NOT_FOUND )
RETURN_IF ( SSH )
RETURN_IF ( SSL_SHUTDOWN_FAILED )
RETURN_IF ( AGAIN )
RETURN_IF ( SSL_CRL_BADFILE )
RETURN_IF ( SSL_ISSUER_ERROR )
RETURN_IF ( FTP_PRET_FAILED )
RETURN_IF ( RTSP_CSEQ_ERROR )
RETURN_IF ( RTSP_SESSION_ERROR )
RETURN_IF ( FTP_BAD_FILE_LIST )
RETURN_IF ( CHUNK_FAILED )
RETURN_IF ( NO_CONNECTION_AVAILABLE )
}
return "UNKNOWN";
#undef RETURN_IF
}
static const char* lcurl_err_multi_mnemo(int err){
#define RETURN_IF(E) case CURLM_##E: return #E;
switch (err){
RETURN_IF ( OK )
RETURN_IF ( CALL_MULTI_PERFORM )
RETURN_IF ( BAD_HANDLE )
RETURN_IF ( BAD_EASY_HANDLE )
RETURN_IF ( OUT_OF_MEMORY )
RETURN_IF ( INTERNAL_ERROR )
RETURN_IF ( BAD_SOCKET )
RETURN_IF ( UNKNOWN_OPTION )
RETURN_IF ( ADDED_ALREADY )
}
return "UNKNOWN";
#undef RETURN_IF
}
static const char* lcurl_err_share_mnemo(int err){
#define RETURN_IF(E) case CURLSHE_##E: return #E;
switch (err){
RETURN_IF ( OK )
RETURN_IF ( BAD_OPTION )
RETURN_IF ( IN_USE )
RETURN_IF ( INVALID )
RETURN_IF ( NOMEM )
RETURN_IF ( NOT_BUILT_IN )
}
return "UNKNOWN";
#undef RETURN_IF
}
static const char* lcurl_err_form_mnemo(int err){
#define RETURN_IF(E) case CURL_FORMADD_##E: return #E;
switch (err){
RETURN_IF ( OK )
RETURN_IF ( MEMORY )
RETURN_IF ( OPTION_TWICE )
RETURN_IF ( NULL )
RETURN_IF ( UNKNOWN_OPTION )
RETURN_IF ( INCOMPLETE )
RETURN_IF ( ILLEGAL_ARRAY )
RETURN_IF ( DISABLED )
}
return "UNKNOWN";
#undef RETURN_IF
}
static const char* _lcurl_err_mnemo(int tp, int err){
switch(tp){
case LCURL_ERROR_EASY : return lcurl_err_easy_mnemo (err);
case LCURL_ERROR_MULTI: return lcurl_err_multi_mnemo(err);
case LCURL_ERROR_SHARE: return lcurl_err_share_mnemo(err);
case LCURL_ERROR_FORM : return lcurl_err_form_mnemo (err);
}
assert(0);
return "<UNSUPPORTED ERROR TYPE>";
}
static const char* _lcurl_err_msg(int tp, int err){
switch(tp){
case LCURL_ERROR_EASY : return curl_easy_strerror (err);
case LCURL_ERROR_MULTI: return curl_multi_strerror(err);
case LCURL_ERROR_SHARE: return curl_share_strerror(err);
case LCURL_ERROR_FORM : return lcurl_err_form_mnemo(err);
}
assert(0);
return "<UNSUPPORTED ERROR TYPE>";
}
static void _lcurl_err_pushstring(lua_State *L, int tp, int err){
lua_pushfstring(L, "[%s] %s (%d)",
_lcurl_err_mnemo(tp, err),
_lcurl_err_msg(tp, err),
err
);
}
//}
//{
int lcurl_error_create(lua_State *L, int error_type, int no){
lcurl_error_t *err = lutil_newudatap(L, lcurl_error_t, LCURL_ERROR);
assert(
(error_type == LCURL_ERROR_EASY ) ||
(error_type == LCURL_ERROR_MULTI) ||
(error_type == LCURL_ERROR_SHARE) ||
(error_type == LCURL_ERROR_FORM ) ||
0
);
err->tp = error_type;
err->no = no;
return 1;
}
static lcurl_error_t *lcurl_geterror_at(lua_State *L, int i){
lcurl_error_t *err = (lcurl_error_t *)lutil_checkudatap (L, i, LCURL_ERROR);
luaL_argcheck (L, err != NULL, 1, LCURL_PREFIX"error object expected");
return err;
}
#define lcurl_geterror(L) lcurl_geterror_at((L),1)
static int lcurl_err_no(lua_State *L){
lcurl_error_t *err = lcurl_geterror(L);
lua_pushinteger(L, err->no);
return 1;
}
static int lcurl_err_msg(lua_State *L){
lcurl_error_t *err = lcurl_geterror(L);
lua_pushstring(L, _lcurl_err_msg(err->tp, err->no));
return 1;
}
static int lcurl_err_mnemo(lua_State *L){
lcurl_error_t *err = lcurl_geterror(L);
lua_pushstring(L, _lcurl_err_mnemo(err->tp, err->no));
return 1;
}
static int lcurl_err_tostring(lua_State *L){
lcurl_error_t *err = lcurl_geterror(L);
_lcurl_err_pushstring(L, err->tp, err->no);
return 1;
}
static int lcurl_err_equal(lua_State *L){
lcurl_error_t *lhs = lcurl_geterror_at(L, 1);
lcurl_error_t *rhs = lcurl_geterror_at(L, 2);
lua_pushboolean(L, ((lhs->no == rhs->no)&&(lhs->tp == rhs->tp))?1:0);
return 1;
}
//}
//{
int lcurl_fail_ex(lua_State *L, int mode, int error_type, int code){
if(mode == LCURL_ERROR_RETURN){
lua_pushnil(L);
lcurl_error_create(L, error_type, code);
return 2;
}
#if LUA_VERSION_NUM >= 502 // lua 5.2
lcurl_error_create(L, error_type, code);
#else
_lcurl_err_pushstring(L, error_type, code);
#endif
assert(LCURL_ERROR_RAISE == mode);
return lua_error(L);
}
int lcurl_fail(lua_State *L, int error_type, int code){
return lcurl_fail_ex(L, LCURL_ERROR_RETURN, error_type, code);
}
//}
int lcurl_error_new(lua_State *L){
int tp = luaL_checkint(L, 1);
int no = luaL_checkint(L, 2);
//! @todo checks error type value
lcurl_error_create(L, tp, no);
return 1;
}
static const struct luaL_Reg lcurl_err_methods[] = {
{"no", lcurl_err_no },
{"msg", lcurl_err_msg },
{"name", lcurl_err_mnemo },
{"mnemo", lcurl_err_mnemo },
{"__tostring", lcurl_err_tostring },
{"__eq", lcurl_err_equal },
{NULL,NULL}
};
void lcurl_error_initlib(lua_State *L, int nup){
if(!lutil_createmetap(L, LCURL_ERROR, lcurl_err_methods, nup))
lua_pop(L, nup);
lua_pop(L, 1);
}

23
src/lcerror.h Normal file
View File

@ -0,0 +1,23 @@
#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_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

393
src/lchttppost.c Normal file
View File

@ -0,0 +1,393 @@
#include "lcurl.h"
#include "lchttppost.h"
#include "lcerror.h"
#include "lcutils.h"
#define LCURL_HTTPPOST_NAME LCURL_PREFIX" HTTPPost"
static const char *LCURL_HTTPPOST = LCURL_HTTPPOST_NAME;
//{
int lcurl_hpost_create(lua_State *L, int error_mode){
lcurl_hpost_t *p = lutil_newudatap(L, lcurl_hpost_t, LCURL_HTTPPOST);
p->post = p->last = 0;
p->storage = lcurl_storage_init(L);
p->err_mode = error_mode;
return 1;
}
lcurl_hpost_t *lcurl_gethpost_at(lua_State *L, int i){
lcurl_hpost_t *p = (lcurl_hpost_t *)lutil_checkudatap (L, i, LCURL_HTTPPOST);
luaL_argcheck (L, p != NULL, 1, LCURL_PREFIX"HTTPPost object expected");
return p;
}
static int lcurl_hpost_add_content(lua_State *L){
// add_buffer(name, data, [type,] [headers])
lcurl_hpost_t *p = lcurl_gethpost(L);
size_t name_len; const char *name = luaL_checklstring(L, 2, &name_len);
size_t cont_len; const char *cont = luaL_checklstring(L, 3, &cont_len);
const char *type = lua_tostring(L, 4);
struct curl_slist *list = lcurl_util_to_slist(L, type?5:4);
struct curl_forms forms[3];
CURLFORMcode code;
int i = 0;
if(type){ forms[i].option = CURLFORM_CONTENTTYPE; forms[i++].value = type; }
if(list){ forms[i].option = CURLFORM_CONTENTHEADER; forms[i++].value = (char*)list; }
forms[i].option = CURLFORM_END;
code = curl_formadd(&p->post, &p->last,
CURLFORM_PTRNAME, name, CURLFORM_NAMELENGTH, name_len,
CURLFORM_PTRCONTENTS, cont, CURLFORM_CONTENTSLENGTH, cont_len,
CURLFORM_ARRAY, forms,
CURLFORM_END);
if(code != CURL_FORMADD_OK){
if(list) curl_slist_free_all(list);
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_FORM, code);
}
lcurl_storage_preserve_value(L, p->storage, 2);
lcurl_storage_preserve_value(L, p->storage, 3);
if(list) lcurl_storage_preserve_slist (L, p->storage, list);
lua_settop(L, 1);
return 1;
}
static int lcurl_hpost_add_buffer(lua_State *L){
// add_buffer(name, filename, data, [type,] [headers])
lcurl_hpost_t *p = lcurl_gethpost(L);
size_t name_len; const char *name = luaL_checklstring(L, 2, &name_len);
const char *buff = luaL_checkstring(L, 3);
size_t cont_len; const char *cont = luaL_checklstring(L, 4, &cont_len);
const char *type = lua_tostring(L, 5);
struct curl_slist *list = lcurl_util_to_slist(L, type?6:5);
struct curl_forms forms[3];
CURLFORMcode code;
int i = 0;
if(type){ forms[i].option = CURLFORM_CONTENTTYPE; forms[i++].value = type; }
if(list){ forms[i].option = CURLFORM_CONTENTHEADER; forms[i++].value = (char*)list; }
forms[i].option = CURLFORM_END;
code = curl_formadd(&p->post, &p->last,
CURLFORM_PTRNAME, name, CURLFORM_NAMELENGTH, name_len,
CURLFORM_BUFFER, buff,
CURLFORM_BUFFERPTR, cont, CURLFORM_BUFFERLENGTH, cont_len,
CURLFORM_ARRAY, forms,
CURLFORM_END);
if(code != CURL_FORMADD_OK){
if(list) curl_slist_free_all(list);
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_FORM, code);
}
lcurl_storage_preserve_value(L, p->storage, 2);
lcurl_storage_preserve_value(L, p->storage, 4);
if(list) lcurl_storage_preserve_slist (L, p->storage, list);
lua_settop(L, 1);
return 1;
}
static int lcurl_hpost_add_file(lua_State *L){
// add_file(name, path, [type, [fname,]] [headers])
// add_file("Picture", "c:\\image.jpg")
// add_file("Picture", "c:\\image.jpg", "image/jpeg")
// add_file("Picture", "c:\\image.jpg", "image/jpeg", {"XDescript: my image"})
// add_file("Picture", "c:\\image.jpg", "image/jpeg", "avatar.jpeg", {"XDescript: my image"})
// add_file("Picture", "c:\\image.jpg", nil, "avatar.jpeg", {"XDescript: my image"})
int top = lua_gettop(L);
lcurl_hpost_t *p = lcurl_gethpost(L);
size_t name_len; const char *name = luaL_checklstring(L, 2, &name_len);
const char *path = luaL_checkstring(L, 3);
const char *type = 0, *fname = 0;
struct curl_slist *list;
struct curl_forms forms[3];
CURLFORMcode code;
int i = 0;
if(top == 4){ /* name, path, type | headers */
if(lua_istable(L, 4))
list = lcurl_util_to_slist(L, 4);
else
type = lua_tostring(L, 4);
}
else if(top > 4){ /* name, path, type, fname | [fname, headers] */
type = lua_tostring(L, 4);
if(top == 5){ /* name, path, type, fname | headers */
if(lua_istable(L, 5))
list = lcurl_util_to_slist(L, 5);
else
fname = lua_tostring(L, 5);
}
else{ /* name, path, type, fname, headers */
fname = lua_tostring(L, 5);
list = lcurl_util_to_slist(L, 6);
}
}
if(type){ forms[i].option = CURLFORM_CONTENTTYPE; forms[i++].value = type; }
if(list){ forms[i].option = CURLFORM_CONTENTHEADER; forms[i++].value = (char*)list; }
forms[i].option = CURLFORM_END;
code = curl_formadd(&p->post, &p->last,
CURLFORM_PTRNAME, name, CURLFORM_NAMELENGTH, name_len,
CURLFORM_FILE, path,
CURLFORM_ARRAY, forms,
CURLFORM_END);
if(code != CURL_FORMADD_OK){
if(list) curl_slist_free_all(list);
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_FORM, code);
}
lcurl_storage_preserve_value(L, p->storage, 2);
if(list) lcurl_storage_preserve_slist (L, p->storage, list);
lua_settop(L, 1);
return 1;
}
static int lcurl_hpost_add_files(lua_State *L){
lcurl_hpost_t *p = lcurl_gethpost(L);
size_t name_len; const char *name = luaL_checklstring(L, 2, &name_len);
int i; int opt_count = 0;
int arr_count = lua_rawlen(L, 3);
struct curl_forms *forms;
CURLFORMcode code;
lua_settop(L, 3);
if(lua_type(L, -1) != LUA_TTABLE){
//! @fixme use library specific error codes
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_FORM, CURL_FORMADD_ILLEGAL_ARRAY);
}
for(i = 1; i <= arr_count; ++i){
int n;
lua_rawgeti(L, 3, i);
if((lua_type(L, -1) != LUA_TTABLE) && (lua_type(L, -1) != LUA_TSTRING)){
//! @fixme use library specific error codes
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_FORM, CURL_FORMADD_ILLEGAL_ARRAY);
}
n = (lua_type(L, -1) == LUA_TSTRING) ? 1: lua_rawlen(L, -1);
if(n == 1) opt_count += 1; // name
else if(n == 2) opt_count += 2; // name and type
else if(n == 3) opt_count += 3; // name, type and filename
else{
//! @fixme use library specific error codes
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_FORM, CURL_FORMADD_ILLEGAL_ARRAY);
}
lua_pop(L, 1);
}
if(opt_count == 0){
lua_settop(L, 1);
return 1;
}
forms = calloc(opt_count + 1, sizeof(struct curl_forms));
if(!forms){
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_FORM, CURL_FORMADD_MEMORY);
}
forms[opt_count].option = CURLFORM_END;
opt_count = 0;
for(i = 1; i <= arr_count; ++i){
int n;
lua_rawgeti(L, 3, i);
if (lua_type(L, -1) == LUA_TSTRING){
forms[opt_count].option = CURLFORM_FILE; forms[opt_count++].value = luaL_checkstring(L, -1);
}
else{
n = lua_rawlen(L, -1);
lua_rawgeti(L, -1, 1);
forms[opt_count].option = CURLFORM_FILE; forms[opt_count++].value = luaL_checkstring(L, -1);
lua_pop(L, 1);
if(n > 1){
lua_rawgeti(L, -1, 2);
forms[opt_count].option = CURLFORM_CONTENTTYPE; forms[opt_count++].value = luaL_checkstring(L, -1);
lua_pop(L, 1);
}
if(n > 2){
lua_rawgeti(L, -1, 3);
forms[opt_count].option = CURLFORM_FILENAME; forms[opt_count++].value = luaL_checkstring(L, -1);
lua_pop(L, 1);
}
}
lua_pop(L, 1);
}
code = curl_formadd(&p->post, &p->last,
CURLFORM_PTRNAME, name, CURLFORM_NAMELENGTH, name_len,
CURLFORM_ARRAY, forms,
CURLFORM_END);
free(forms);
if(code != CURL_FORMADD_OK){
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_FORM, code);
}
lua_settop(L, 1);
return 1;
}
static size_t lcurl_hpost_getter_by_buffer(void *arg, const char *buf, size_t len){
luaL_Buffer *b = arg;
luaL_addlstring(b, buf, len);
return len;
}
static size_t call_writer(lua_State *L, int fn, int ctx, const char *buf, size_t len){
int top = lua_gettop(L);
int n = 1; // number of args
lua_Number ret = (lua_Number)len;
lua_pushvalue(L, fn);
if(ctx){
lua_pushvalue(L, ctx);
n += 1;
}
lua_pushlstring(L, buf, len);
if(lua_pcall(L, n, LUA_MULTRET, 0)) return 0;
if(lua_gettop(L) > top){
if(lua_isnil(L, top + 1)) return 0;
if(lua_isboolean(L, top + 1)){
if(!lua_toboolean(L, top + 1)) ret = 0;
}
else ret = lua_tonumber(L, top + 1);
}
lua_settop(L, top);
return (size_t)ret;
}
static size_t lcurl_hpost_getter_by_callback1(void *arg, const char *buf, size_t len){
lua_State *L = arg;
assert(2 == lua_gettop(L));
return call_writer(L, 2, 0, buf, len);
}
static size_t lcurl_hpost_getter_by_callback2(void *arg, const char *buf, size_t len){
lua_State *L = arg;
assert(3 == lua_gettop(L));
return call_writer(L, 2, 3, buf, len);
}
static int lcurl_hpost_get(lua_State *L){
// get()
// get(fn [, ctx])
// get(object)
lcurl_hpost_t *p = lcurl_gethpost(L);
CURLcode code;
int top;
if(lua_isnoneornil(L, 2)){
luaL_Buffer b;
luaL_buffinit(L, &b);
code = curl_formget(p->post, &b, lcurl_hpost_getter_by_buffer);
if(code != CURLE_OK){
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_CURL, code);
}
luaL_pushresult(&b);
return 1;
}
if(lua_isfunction(L, 2)){
if(lua_gettop(L) == 2){
top = 2;
code = curl_formget(p->post, L, lcurl_hpost_getter_by_callback1);
}
else{
top = 3;
lua_settop(L, 3);
code = curl_formget(p->post, L, lcurl_hpost_getter_by_callback2);
}
}
else if(lua_isuserdata(L, 2) || lua_istable(L, 2)){
lua_settop(L, 2);
lua_getfield(L, 2, "write");
luaL_argcheck(L, lua_isfunction(L, -1), 2, "write method not found in object");
assert(3 == lua_gettop(L));
lua_insert(L, -2);
top = 3;
code = curl_formget(p->post, L, lcurl_hpost_getter_by_callback2);
}
else{
lua_pushliteral(L, "invalid writer type");
return lua_error(L);
}
if((CURLcode)-1 == code){
if(((lua_gettop(L) == top+1))&&(lua_isstring(L, -1))){
return lua_error(L);
}
return lua_gettop(L) - top;
}
if(code != CURLE_OK){
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_CURL, code);
}
lua_settop(L, 1);
return 1;
}
static int lcurl_hpost_storage(lua_State *L){
lcurl_hpost_t *p = lcurl_gethpost(L);
lua_rawgeti(L, LCURL_LUA_REGISTRY, p->storage);
return 1;
}
static int lcurl_hpost_free(lua_State *L){
lcurl_hpost_t *p = lcurl_gethpost(L);
if(p->post){
curl_formfree(p->post);
p->post = p->last = 0;
}
if(p->storage != LUA_NOREF){
lcurl_storage_free(L, p->storage);
p->storage = LUA_NOREF;
}
return 0;
}
//}
static const struct luaL_Reg lcurl_hpost_methods[] = {
{"add_content", lcurl_hpost_add_content },
{"add_buffer", lcurl_hpost_add_buffer },
{"add_file", lcurl_hpost_add_file },
{"add_files", lcurl_hpost_add_files },
{"storage", lcurl_hpost_storage },
{"get", lcurl_hpost_get },
{"free", lcurl_hpost_free },
{"__gc", lcurl_hpost_free },
{NULL,NULL}
};
void lcurl_hpost_initlib(lua_State *L, int nup){
if(!lutil_createmetap(L, LCURL_HTTPPOST, lcurl_hpost_methods, nup))
lua_pop(L, nup);
lua_pop(L, 1);
}

22
src/lchttppost.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef _LCHTTPPOST_H_
#define _LCHTTPPOST_H_
#include "lcurl.h"
typedef struct lcurl_hpost_tag{
struct curl_httppost *post;
struct curl_httppost *last;
int storage;
int err_mode;
}lcurl_hpost_t;
int lcurl_hpost_create(lua_State *L, int error_mode);
void lcurl_hpost_initlib(lua_State *L, int nup);
lcurl_hpost_t *lcurl_gethpost_at(lua_State *L, int i);
#define lcurl_gethpost(L) lcurl_gethpost_at((L),1)
#endif

44
src/lcinfoeasy.h Normal file
View File

@ -0,0 +1,44 @@
OPT_ENTRY( effective_url, EFFECTIVE_URL, STR, 0)
OPT_ENTRY( response_code, RESPONSE_CODE, LNG, 0)
OPT_ENTRY( http_connectcode, HTTP_CONNECTCODE, LNG, 0)
OPT_ENTRY( filetime, FILETIME, LNG, 0)
OPT_ENTRY( total_time, TOTAL_TIME, DBL, 0)
OPT_ENTRY( namelookup_time, NAMELOOKUP_TIME, DBL, 0)
OPT_ENTRY( connect_time, CONNECT_TIME, DBL, 0)
OPT_ENTRY( appconnect_time, APPCONNECT_TIME, DBL, 0)
OPT_ENTRY( pretransfer_time, PRETRANSFER_TIME, DBL, 0)
OPT_ENTRY( starttransfer_time, STARTTRANSFER_TIME, DBL, 0)
OPT_ENTRY( redirect_time, REDIRECT_TIME, DBL, 0)
OPT_ENTRY( redirect_count, REDIRECT_COUNT, LNG, 0)
OPT_ENTRY( redirect_url, REDIRECT_URL, STR, 0)
OPT_ENTRY( size_upload, SIZE_UPLOAD, DBL, 0)
OPT_ENTRY( size_download, SIZE_DOWNLOAD, DBL, 0)
OPT_ENTRY( speed_download, SPEED_DOWNLOAD, DBL, 0)
OPT_ENTRY( speed_upload, SPEED_UPLOAD, DBL, 0)
OPT_ENTRY( header_size, HEADER_SIZE, LNG, 0)
OPT_ENTRY( request_size, REQUEST_SIZE, LNG, 0)
OPT_ENTRY( ssl_verifyresult, SSL_VERIFYRESULT, LNG, 0)
OPT_ENTRY( ssl_engines, SSL_ENGINES, LST, 0)
OPT_ENTRY( content_length_download, CONTENT_LENGTH_DOWNLOAD, DBL, 0)
OPT_ENTRY( content_length_upload, CONTENT_LENGTH_UPLOAD, DBL, 0)
OPT_ENTRY( content_type, CONTENT_TYPE, STR, 0)
OPT_ENTRY( httpauth_avail, HTTPAUTH_AVAIL, LNG, 0)
OPT_ENTRY( proxyauth_avail, PROXYAUTH_AVAIL, LNG, 0)
OPT_ENTRY( os_errno, OS_ERRNO, LNG, 0)
OPT_ENTRY( num_connects, NUM_CONNECTS, LNG, 0)
OPT_ENTRY( primary_ip, PRIMARY_IP, STR, 0)
OPT_ENTRY( primary_port, PRIMARY_PORT, LNG, 0)
OPT_ENTRY( local_ip, LOCAL_IP, STR, 0)
OPT_ENTRY( local_port, LOCAL_PORT, LNG, 0)
OPT_ENTRY( cookielist, COOKIELIST, LST, 0)
OPT_ENTRY( lastsocket, LASTSOCKET, LNG, 0)
OPT_ENTRY( ftp_entry_path, FTP_ENTRY_PATH, STR, 0)
OPT_ENTRY( condition_unmet, CONDITION_UNMET, LNG, 0)
OPT_ENTRY( rtsp_session_id, RTSP_SESSION_ID, STR, 0)
OPT_ENTRY( rtsp_client_cseq, RTSP_CLIENT_CSEQ, LNG, 0)
OPT_ENTRY( rtsp_server_cseq, RTSP_SERVER_CSEQ, LNG, 0)
OPT_ENTRY( rtsp_cseq_recv, RTSP_CSEQ_RECV, LNG, 0)
// OPT_ENTRY( PRIVATE, void )
// OPT_ENTRY( CERTINFO, struct curl_certinfo *
// OPT_ENTRY( TLS_SESSION, struct curl_tlssessioninfo *

159
src/lcopteasy.h Normal file
View File

@ -0,0 +1,159 @@
#undef INTERFACE
#undef BUFFERSIZE
#undef TCP_NODELAY
#undef TCP_KEEPALIVE
/* Before version 7.17.0, strings were not copied.
Instead the user was forced keep them available
until libcurl no longer needed them.
*/
#ifndef LCURL_STORE_STRING
# define LCURL_STORE_STRING 0
#endif
OPT_ENTRY( verbose, VERBOSE, LNG, 0 )
OPT_ENTRY( header, HEADER, LNG, 0 )
OPT_ENTRY( noprogress, NOPROGRESS, LNG, 0 )
OPT_ENTRY( nosignal, NOSIGNAL, LNG, 0 )
OPT_ENTRY( wildcardmatch, WILDCARDMATCH, LNG, 0 )
OPT_ENTRY( url, URL, STR, LCURL_STORE_STRING )
OPT_ENTRY( failonerror, FAILONERROR, LNG, 0 )
OPT_ENTRY( protocols, PROTOCOLS, LNG, 0 )
OPT_ENTRY( redir_protocols, REDIR_PROTOCOLS, LNG, 0 )
OPT_ENTRY( proxy, PROXY, STR, LCURL_STORE_STRING )
OPT_ENTRY( proxyport, PROXYPORT, LNG, 0 )
OPT_ENTRY( proxytype, PROXYTYPE, LNG, 0 )
OPT_ENTRY( noproxy, NOPROXY, STR, LCURL_STORE_STRING )
OPT_ENTRY( httpproxytunnel, HTTPPROXYTUNNEL, LNG, 0 )
OPT_ENTRY( socks5_gssapi_service, SOCKS5_GSSAPI_SERVICE, STR, LCURL_STORE_STRING )
OPT_ENTRY( socks5_gssapi_nec, SOCKS5_GSSAPI_NEC, LNG, 0 )
OPT_ENTRY( interface, INTERFACE, STR, LCURL_STORE_STRING )
OPT_ENTRY( localport, LOCALPORT, LNG, 0 )
OPT_ENTRY( localportrange, LOCALPORTRANGE, LNG, 0 )
OPT_ENTRY( dns_cache_timeout, DNS_CACHE_TIMEOUT, LNG, 0 )
OPT_ENTRY( dns_use_global_cache, DNS_USE_GLOBAL_CACHE, LNG, 0 )
OPT_ENTRY( buffersize, BUFFERSIZE, LNG, 0 )
OPT_ENTRY( port, PORT, LNG, 0 )
OPT_ENTRY( tcp_nodelay, TCP_NODELAY, LNG, 0 )
OPT_ENTRY( address_scope, ADDRESS_SCOPE, LNG, 0 )
OPT_ENTRY( tcp_keepalive, TCP_KEEPALIVE, LNG, 0 )
OPT_ENTRY( tcp_keepidle, TCP_KEEPIDLE, LNG, 0 )
OPT_ENTRY( tcp_keepintvl, TCP_KEEPINTVL, LNG, 0 )
OPT_ENTRY( netrc, NETRC, LNG, 0 )
OPT_ENTRY( netrc_file, NETRC_FILE, STR, LCURL_STORE_STRING )
OPT_ENTRY( userpwd, USERPWD, STR, LCURL_STORE_STRING )
OPT_ENTRY( proxyuserpwd, PROXYUSERPWD, STR, LCURL_STORE_STRING )
OPT_ENTRY( username, USERNAME, STR, LCURL_STORE_STRING )
OPT_ENTRY( password, PASSWORD, STR, LCURL_STORE_STRING )
OPT_ENTRY( login_options, LOGIN_OPTIONS, STR, LCURL_STORE_STRING )
OPT_ENTRY( proxyusername, PROXYUSERNAME, STR, LCURL_STORE_STRING )
OPT_ENTRY( proxypassword, PROXYPASSWORD, STR, LCURL_STORE_STRING )
OPT_ENTRY( httpauth, HTTPAUTH, STR, LCURL_STORE_STRING )
OPT_ENTRY( tlsauth_username, TLSAUTH_USERNAME, STR, LCURL_STORE_STRING )
OPT_ENTRY( tlsauth_password, TLSAUTH_PASSWORD, STR, LCURL_STORE_STRING )
OPT_ENTRY( proxyauth, PROXYAUTH, LNG, 0 )
OPT_ENTRY( sasl_ir, SASL_IR, LNG, 0 )
OPT_ENTRY( xoauth2_bearer, XOAUTH2_BEARER, STR, LCURL_STORE_STRING )
OPT_ENTRY( autoreferer, AUTOREFERER, LNG, 0 )
OPT_ENTRY( accept_encoding, ACCEPT_ENCODING, STR, LCURL_STORE_STRING )
OPT_ENTRY( transfer_encoding, TRANSFER_ENCODING, LNG, 0 )
OPT_ENTRY( followlocation, FOLLOWLOCATION, LNG, 0 )
OPT_ENTRY( unrestricted_auth, UNRESTRICTED_AUTH, LNG, 0 )
OPT_ENTRY( maxredirs, MAXREDIRS, LNG, 0 )
OPT_ENTRY( postredir, POSTREDIR, LNG, 0 )
OPT_ENTRY( put, PUT, LNG, 0 )
OPT_ENTRY( post, POST, LNG, 0 )
OPT_ENTRY( referer, REFERER, STR, LCURL_STORE_STRING )
OPT_ENTRY( useragent, USERAGENT, STR, LCURL_STORE_STRING )
OPT_ENTRY( headeropt, HEADEROPT, LNG, 0 )
OPT_ENTRY( httpheader, HTTPHEADER, LST, 0 )
OPT_ENTRY( proxyheader, PROXYHEADER, LST, 0 )
OPT_ENTRY( http200aliases, HTTP200ALIASES, LST, 0 )
OPT_ENTRY( cookie, COOKIE, STR, LCURL_STORE_STRING )
OPT_ENTRY( cookiefile, COOKIEFILE, STR, LCURL_STORE_STRING )
OPT_ENTRY( cookiejar, COOKIEJAR, STR, LCURL_STORE_STRING )
OPT_ENTRY( cookiesession, COOKIESESSION, LNG, 0 )
OPT_ENTRY( cookielist, COOKIELIST, STR, LCURL_STORE_STRING )
OPT_ENTRY( httpget, HTTPGET, LNG, 0 )
OPT_ENTRY( http_version, HTTP_VERSION, LNG, 0 )
OPT_ENTRY( ignore_content_length, IGNORE_CONTENT_LENGTH, LNG, 0 )
OPT_ENTRY( http_content_decoding, HTTP_CONTENT_DECODING, LNG, 0 )
OPT_ENTRY( http_transfer_decoding, HTTP_TRANSFER_DECODING, LNG, 0 )
OPT_ENTRY( expect_100_timeout_ms, EXPECT_100_TIMEOUT_MS, LNG, 0 )
OPT_ENTRY( mail_from, MAIL_FROM, STR, LCURL_STORE_STRING )
OPT_ENTRY( mail_rcpt, MAIL_RCPT, STR, LCURL_STORE_STRING )
OPT_ENTRY( mail_auth, MAIL_AUTH, STR, LCURL_STORE_STRING )
OPT_ENTRY( tftp_blksize, TFTP_BLKSIZE, LNG, 0 )
OPT_ENTRY( ftpport, FTPPORT, STR, LCURL_STORE_STRING )
OPT_ENTRY( quote, QUOTE, LST, 0 )
OPT_ENTRY( postquote, POSTQUOTE, LST, 0 )
OPT_ENTRY( prequote, PREQUOTE, STR, LCURL_STORE_STRING )
OPT_ENTRY( dirlistonly, DIRLISTONLY, LNG, 0 )
OPT_ENTRY( append, APPEND, LNG, 0 )
OPT_ENTRY( ftp_use_eprt, FTP_USE_EPRT, LNG, 0 )
OPT_ENTRY( ftp_use_epsv, FTP_USE_EPSV, LNG, 0 )
OPT_ENTRY( ftp_use_pret, FTP_USE_PRET, LNG, 0 )
OPT_ENTRY( ftp_create_missing_dirs, FTP_CREATE_MISSING_DIRS, LNG, 0 )
OPT_ENTRY( ftp_response_timeout, FTP_RESPONSE_TIMEOUT, LNG, 0 )
OPT_ENTRY( ftp_alternative_to_user, FTP_ALTERNATIVE_TO_USER, STR, LCURL_STORE_STRING )
OPT_ENTRY( ftp_skip_pasv_ip, FTP_SKIP_PASV_IP, LNG, 0 )
OPT_ENTRY( ftpsslauth, FTPSSLAUTH, LNG, 0 )
OPT_ENTRY( ftp_ssl_ccc, FTP_SSL_CCC, LNG, 0 )
OPT_ENTRY( ftp_account, FTP_ACCOUNT, STR, LCURL_STORE_STRING )
OPT_ENTRY( ftp_filemethod, FTP_FILEMETHOD, LNG, 0 )
OPT_ENTRY( transfertext, TRANSFERTEXT, LNG, 0 )
OPT_ENTRY( proxy_transfer_mode, PROXY_TRANSFER_MODE, LNG, 0 )
OPT_ENTRY( crlf, CRLF, LNG, 0 )
OPT_ENTRY( range, RANGE, STR, LCURL_STORE_STRING )
OPT_ENTRY( resume_from, RESUME_FROM, LNG, 0 )
OPT_ENTRY( resume_from_large, RESUME_FROM_LARGE, LNG, 0 )
OPT_ENTRY( customrequest, CUSTOMREQUEST, STR, LCURL_STORE_STRING )
OPT_ENTRY( filetime, FILETIME, LNG, 0 )
OPT_ENTRY( nobody, NOBODY, LNG, 0 )
OPT_ENTRY( infilesize, INFILESIZE, LNG, 0 )
OPT_ENTRY( infilesize_large, INFILESIZE_LARGE, LNG, 0 )
OPT_ENTRY( upload, UPLOAD, LNG, 0 )
OPT_ENTRY( maxfilesize, MAXFILESIZE, LNG, 0 )
OPT_ENTRY( maxfilesize_large, MAXFILESIZE_LARGE, LNG, 0 )
OPT_ENTRY( timecondition, TIMECONDITION, LNG, 0 )
OPT_ENTRY( timevalue, TIMEVALUE, LNG, 0 )
OPT_ENTRY( timeout, TIMEOUT, LNG, 0 )
OPT_ENTRY( timeout_ms, TIMEOUT_MS, LNG, 0 )
OPT_ENTRY( low_speed_limit, LOW_SPEED_LIMIT, LNG, 0 )
OPT_ENTRY( low_speed_time, LOW_SPEED_TIME, LNG, 0 )
OPT_ENTRY( max_send_speed_large, MAX_SEND_SPEED_LARGE, LNG, 0 )
OPT_ENTRY( max_recv_speed_large, MAX_RECV_SPEED_LARGE, LNG, 0 )
OPT_ENTRY( maxconnects, MAXCONNECTS, LNG, 0 )
OPT_ENTRY( fresh_connect, FRESH_CONNECT, LNG, 0 )
OPT_ENTRY( forbid_reuse, FORBID_REUSE, LNG, 0 )
OPT_ENTRY( connecttimeout, CONNECTTIMEOUT, LNG, 0 )
OPT_ENTRY( connecttimeout_ms, CONNECTTIMEOUT_MS, LNG, 0 )
OPT_ENTRY( ipresolve, IPRESOLVE, LNG, 0 )
OPT_ENTRY( connect_only, CONNECT_ONLY, LNG, 0 )
OPT_ENTRY( use_ssl, USE_SSL, LNG, 0 )
OPT_ENTRY( resolve, RESOLVE, LST, 0 )
OPT_ENTRY( dns_interface, DNS_INTERFACE, STR, LCURL_STORE_STRING )
OPT_ENTRY( dns_local_ip4, DNS_LOCAL_IP4, STR, LCURL_STORE_STRING )
OPT_ENTRY( dns_local_ip6, DNS_LOCAL_IP6, STR, LCURL_STORE_STRING )
OPT_ENTRY( accepttimeout_ms, ACCEPTTIMEOUT_MS, LNG, 0 )
OPT_ENTRY( ssh_auth_types, SSH_AUTH_TYPES, LNG, 0)
OPT_ENTRY( ssh_host_public_key_md5, SSH_HOST_PUBLIC_KEY_MD5, STR, 0)
OPT_ENTRY( ssh_public_keyfile, SSH_PUBLIC_KEYFILE, STR, 0)
OPT_ENTRY( ssh_private_keyfile, SSH_PRIVATE_KEYFILE, STR, 0)
OPT_ENTRY( ssh_knownhosts, SSH_KNOWNHOSTS, STR, 0)
OPT_ENTRY( new_file_perms, NEW_FILE_PERMS, LNG, 0)
OPT_ENTRY( new_directory_perms, NEW_DIRECTORY_PERMS, LNG, 0)
OPT_ENTRY( telnetoptions, TELNETOPTIONS, LST, 0)

73
src/lcurl.c Normal file
View File

@ -0,0 +1,73 @@
#include "lcurl.h"
#include "lceasy.h"
#include "lcerror.h"
#include "lchttppost.h"
static int lcurl_easy_new_safe(lua_State *L){
return lcurl_easy_create(L, LCURL_ERROR_RETURN);
}
static int lcurl_hpost_new_safe(lua_State *L){
return lcurl_hpost_create(L, LCURL_ERROR_RETURN);
}
static int lcurl_easy_new(lua_State *L){
return lcurl_easy_create(L, LCURL_ERROR_RAISE);
}
static int lcurl_hpost_new(lua_State *L){
return lcurl_hpost_create(L, LCURL_ERROR_RAISE);
}
static const struct luaL_Reg lcurl_functions[] = {
{"error", lcurl_error_new },
{"httppost", lcurl_hpost_new },
{"easy", lcurl_easy_new },
{NULL,NULL}
};
static const struct luaL_Reg lcurl_functions_safe[] = {
{"error", lcurl_error_new },
{"httppost", lcurl_hpost_new_safe },
{"easy", lcurl_easy_new_safe },
{NULL,NULL}
};
static volatile int LCURL_INIT = 0;
static const char* LCURL_REGISTRY = "LCURL Registry";
static int luaopen_lcurl_(lua_State *L, const struct luaL_Reg *func){
if(!LCURL_INIT){
curl_global_init(CURL_GLOBAL_DEFAULT);
LCURL_INIT = 1;
}
lua_rawgetp(L, LUA_REGISTRYINDEX, LCURL_REGISTRY);
if(!lua_istable(L, -1)){ /* registry */
lua_pop(L, 1);
lua_newtable(L);
}
lua_newtable(L); /* library */
lua_pushvalue(L, -2); luaL_setfuncs(L, func, 1);
lua_pushvalue(L, -2); lcurl_error_initlib(L, 1);
lua_pushvalue(L, -2); lcurl_hpost_initlib(L, 1);
lua_pushvalue(L, -2); lcurl_easy_initlib (L, 1);
lua_pushvalue(L, -2); lua_rawsetp(L, LUA_REGISTRYINDEX, LCURL_REGISTRY);
lua_remove(L, -2); /* registry */
return 1;
}
__declspec(dllexport)
int luaopen_lcurl(lua_State *L){ return luaopen_lcurl_(L, lcurl_functions); }
__declspec(dllexport)
int luaopen_lcurl_safe(lua_State *L){ return luaopen_lcurl_(L, lcurl_functions_safe); }

16
src/lcurl.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef _LCURL_H_
#define _LCURL_H_
#include "l52util.h"
#include "curl/curl.h"
#include "curl/easy.h"
#include "curl/multi.h"
#include <assert.h>
#define LCURL_PREFIX "LcURL"
#define LCURL_LUA_REGISTRY lua_upvalueindex(1)
#endif

101
src/lcutils.c Normal file
View File

@ -0,0 +1,101 @@
#include "lcurl.h"
#include "lcutils.h"
#include "lcerror.h"
int lcurl_storage_init(lua_State *L){
lua_newtable(L);
return luaL_ref(L, LCURL_LUA_REGISTRY);
}
void lcurl_storage_preserve_value(lua_State *L, int storage, int i){
assert(i > 0);
luaL_checkany(L, i);
lua_rawgeti(L, LCURL_LUA_REGISTRY, storage);
lua_pushvalue(L, i); lua_pushboolean(L, 1); lua_rawset(L, -3);
lua_pop(L, 1);
}
int lcurl_storage_preserve_slist(lua_State *L, int storage, struct curl_slist * list){
int r;
lua_rawgeti(L, LCURL_LUA_REGISTRY, storage);
lua_rawgeti(L, -1, 1); // list storage
if(!lua_istable(L, -1)){
lua_pop(L, 1);
lua_newtable(L);
lua_pushvalue(L, -1);
lua_rawseti(L, -3, 1);
}
lua_pushlightuserdata(L, list);
r = luaL_ref(L, -2);
lua_pop(L, 2);
return r;
}
struct curl_slist* lcurl_storage_remove_slist(lua_State *L, int storage, int idx){
struct curl_slist* list;
assert(idx != LUA_NOREF);
lua_rawgeti(L, LCURL_LUA_REGISTRY, storage);
lua_rawgeti(L, -1, 1); // list storage
lua_rawgeti(L, -1, idx);
list = lua_touserdata(L, -1);
assert(list);
luaL_unref(L, -2, idx);
lua_pop(L, 3);
return list;
}
void lcurl_storage_free(lua_State *L, int storage){
lua_rawgeti(L, LCURL_LUA_REGISTRY, storage);
lua_rawgeti(L, -1, 1); // list storage
if(lua_istable(L, -1)){
lua_pushnil(L);
while(lua_next(L, -2) != 0){
struct curl_slist * list = lua_touserdata(L, -1);
curl_slist_free_all(list);
lua_pushvalue(L, -2); lua_pushnil(L);
lua_rawset(L, -5);
lua_pop(L, 1);
}
}
lua_pop(L, 1);
luaL_unref(L, LCURL_LUA_REGISTRY, storage);
}
struct curl_slist* lcurl_util_array_to_slist(lua_State *L, int t){
struct curl_slist *list = NULL;
int i, n = lua_rawlen(L, t);
assert(lua_type(L, t) == LUA_TTABLE);
for(i = 1; i <= n; ++i){
lua_rawgeti(L, t, i);
list = curl_slist_append(list, lua_tostring(L, -1));
lua_pop(L, 1);
}
return list;
}
struct curl_slist* lcurl_util_to_slist(lua_State *L, int t){
if(lua_type(L, t) == LUA_TTABLE){
return lcurl_util_array_to_slist(L, t);
}
return 0;
}
void lcurl_util_slist_set(lua_State *L, int t, struct curl_slist* list){
int i;
t = lua_absindex(L, t);
for(i = 0;list;list = list->next){
lua_pushstring(L, list->data);
lua_rawseti(L, t, ++i);
}
}
void lcurl_util_slist_to_table(lua_State *L, struct curl_slist* list){
lua_newtable(L);
lcurl_util_slist_set(L, -1, list);
}

24
src/lcutils.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef _LCUTILS_H_
#define _LCUTILS_H_
#include "lcurl.h"
int lcurl_storage_init(lua_State *L);
void lcurl_storage_preserve_value(lua_State *L, int storage, int i);
int lcurl_storage_preserve_slist(lua_State *L, int storage, struct curl_slist * list);
struct curl_slist* lcurl_storage_remove_slist(lua_State *L, int storage, int idx);
void lcurl_storage_free(lua_State *L, int storage);
struct curl_slist* lcurl_util_array_to_slist(lua_State *L, int t);
struct curl_slist* lcurl_util_to_slist(lua_State *L, int t);
void lcurl_util_slist_set(lua_State *L, int t, struct curl_slist* list);
void lcurl_util_slist_to_table(lua_State *L, struct curl_slist* list);
#endif