diff options
Diffstat (limited to 'source/luametatex/source/luaoptional/lmtcurl.c')
-rw-r--r-- | source/luametatex/source/luaoptional/lmtcurl.c | 506 |
1 files changed, 506 insertions, 0 deletions
diff --git a/source/luametatex/source/luaoptional/lmtcurl.c b/source/luametatex/source/luaoptional/lmtcurl.c new file mode 100644 index 000000000..6a54174e5 --- /dev/null +++ b/source/luametatex/source/luaoptional/lmtcurl.c @@ -0,0 +1,506 @@ +/* + See license.txt in the root of this project. +*/ + +# include "luametatex.h" +# include "lmtoptional.h" + +typedef void* curl_instance ; +typedef int curl_return_code ; +typedef int curl_error_code ; + +typedef enum curl_option_type { + curl_ignore = 0, + curl_integer = 1, + curl_string = 2, + curl_function = 3, /* ignored */ + curl_offset = 4, /* ignored */ +} curl_option_type; + +/*tex At the \LUA\ end we can have a mapping of useful ones, */ + +static const int curl_options[] = { + curl_ignore, /* 0 */ + curl_string, /* 1 file | writedata */ + curl_string, /* 2 url */ + curl_integer, /* 3 port */ + curl_string, /* 4 proxy */ + curl_string, /* 5 userpwd */ + curl_string, /* 6 proxyuserpwd */ + curl_string, /* 7 range */ + curl_ignore, /* 8 */ + curl_string, /* 9 infile | readdata */ + curl_string, /* 10 errorbuffer */ + curl_function, /* 11 writefunction */ + curl_function, /* 12 readfunction */ + curl_integer, /* 13 timeout */ + curl_integer, /* 14 infilesize */ + curl_string, /* 15 postfields */ + curl_string, /* 16 referer */ + curl_string, /* 17 ftpport */ + curl_string, /* 18 useragent */ + curl_integer, /* 19 low_speed_limit */ + curl_integer, /* 20 low_speed_time */ + curl_integer, /* 21 resume_from */ + curl_string, /* 22 cookie */ + curl_string, /* 23 httpheader | rtspheader */ + curl_string, /* 24 httppost */ + curl_string, /* 25 sslcert */ + curl_string, /* 26 keypasswd */ + curl_integer, /* 27 crlf */ + curl_string, /* 28 quote */ + curl_string, /* 29 writeheader | headerdata */ + curl_ignore, /* 30 */ + curl_string, /* 31 cookiefile */ + curl_integer, /* 32 sslversion */ + curl_integer, /* 33 timecondition */ + curl_integer, /* 34 timevalue */ + curl_ignore, /* 35 */ + curl_string, /* 36 customrequest */ + curl_string, /* 37 stderr */ + curl_ignore, /* 38 */ + curl_string, /* 39 postquote */ + curl_string, /* 40 writeinfo */ + curl_integer, /* 41 verbose */ + curl_integer, /* 42 header */ + curl_integer, /* 43 noprogress */ + curl_integer, /* 44 nobody */ + curl_integer, /* 45 failonerror */ + curl_integer, /* 46 upload */ + curl_integer, /* 47 post */ + curl_integer, /* 48 dirlistonly */ + curl_ignore, /* 49 */ + curl_integer, /* 50 append */ + curl_integer, /* 51 netrc */ + curl_integer, /* 52 followlocation */ + curl_integer, /* 53 transfertext */ + curl_integer, /* 54 put */ + curl_ignore, /* 55 */ + curl_function, /* 56 progressfunction */ + curl_string, /* 57 xferinfodata | progressdata */ + curl_integer, /* 58 autoreferer */ + curl_integer, /* 59 proxyport */ + curl_integer, /* 60 postfieldsize */ + curl_integer, /* 61 httpproxytunnel */ + curl_string, /* 62 interface */ + curl_string, /* 63 krblevel */ + curl_integer, /* 64 ssl_verifypeer */ + curl_string, /* 65 cainfo */ + curl_ignore, /* 66 */ + curl_ignore, /* 67 */ + curl_integer, /* 68 maxredirs */ + curl_integer, /* 69 filetime */ + curl_string, /* 70 telnetoptions */ + curl_integer, /* 71 maxconnects */ + curl_integer, /* 72 closepolicy */ + curl_ignore, /* 73 */ + curl_integer, /* 74 fresh_connect */ + curl_integer, /* 75 forbid_reuse */ + curl_string, /* 76 random_file */ + curl_string, /* 77 egdsocket */ + curl_integer, /* 78 connecttimeout */ + curl_function, /* 79 headerfunction */ + curl_integer, /* 80 httpget */ + curl_integer, /* 81 ssl_verifyhost */ + curl_string, /* 82 cookiejar */ + curl_string, /* 83 ssl_cipher_list */ + curl_integer, /* 84 http_version */ + curl_integer, /* 85 ftp_use_epsv */ + curl_string, /* 86 sslcerttype */ + curl_string, /* 87 sslkey */ + curl_string, /* 88 sslkeytype */ + curl_string, /* 89 sslengine */ + curl_integer, /* 90 sslengine_default */ + curl_integer, /* 91 dns_use_global_cache */ + curl_integer, /* 92 dns_cache_timeout */ + curl_string, /* 93 prequote */ + curl_function, /* 94 debugfunction */ + curl_string, /* 95 debugdata */ + curl_integer, /* 96 cookiesession */ + curl_string, /* 97 capath */ + curl_integer, /* 98 buffersize */ + curl_integer, /* 99 nosignal */ + curl_string, /* 100 share */ + curl_integer, /* 101 proxytype */ + curl_string, /* 102 accept_encoding */ + curl_string, /* 103 private */ + curl_string, /* 104 http200aliases */ + curl_integer, /* 105 unrestricted_auth */ + curl_integer, /* 106 ftp_use_eprt */ + curl_integer, /* 107 httpauth */ + curl_function, /* 108 ssl_ctx_function */ + curl_string, /* 109 ssl_ctx_data */ + curl_integer, /* 110 ftp_create_missing_dirs */ + curl_integer, /* 111 proxyauth */ + curl_integer, /* 112 server_response_timeout | ftp_response_timeout */ + curl_integer, /* 113 ipresolve */ + curl_integer, /* 114 maxfilesize */ + curl_offset, /* 115 infilesize_large */ + curl_offset, /* 116 resume_from_large */ + curl_offset, /* 117 maxfilesize_large */ + curl_string, /* 118 netrc_file */ + curl_integer, /* 119 use_ssl */ + curl_offset, /* 120 postfieldsize_large */ + curl_integer, /* 121 tcp_nodelay */ + curl_ignore, /* 122 */ + curl_ignore, /* 123 */ + curl_ignore, /* 124 */ + curl_ignore, /* 125 */ + curl_ignore, /* 126 */ + curl_ignore, /* 127 */ + curl_ignore, /* 128 */ + curl_integer, /* 129 ftpsslauth */ + curl_function, /* 130 ioctlfunction */ + curl_string, /* 131 ioctldata */ + curl_ignore, /* 132 */ + curl_ignore, /* 133 */ + curl_string, /* 134 ftp_account */ + curl_string, /* 135 cookielist */ + curl_integer, /* 136 ignore_content_length */ + curl_integer, /* 137 ftp_skip_pasv_ip */ + curl_integer, /* 138 ftp_filemethod */ + curl_integer, /* 139 localport */ + curl_integer, /* 140 localportrange */ + curl_integer, /* 141 connect_only */ + curl_function, /* 142 conv_from_network_function */ + curl_function, /* 143 conv_to_network_function */ + curl_function, /* 144 conv_from_utf8_function */ + curl_offset, /* 145 max_send_speed_large */ + curl_offset, /* 146 max_recv_speed_large */ + curl_string, /* 147 ftp_alternative_to_user */ + curl_function, /* 148 sockoptfunction */ + curl_string, /* 149 sockoptdata */ + curl_integer, /* 150 ssl_sessionid_cache */ + curl_integer, /* 151 ssh_auth_types */ + curl_string, /* 152 ssh_public_keyfile */ + curl_string, /* 153 ssh_private_keyfile */ + curl_integer, /* 154 ftp_ssl_ccc */ + curl_integer, /* 155 timeout_ms */ + curl_integer, /* 156 connecttimeout_ms */ + curl_integer, /* 157 http_transfer_decoding */ + curl_integer, /* 158 http_content_decoding */ + curl_integer, /* 159 new_file_perms */ + curl_integer, /* 160 new_directory_perms */ + curl_integer, /* 161 postredir */ + curl_string, /* 162 ssh_host_public_key_md5 */ + curl_function, /* 163 opensocketfunction */ + curl_string, /* 164 opensocketdata */ + curl_string, /* 165 copypostfields */ + curl_integer, /* 166 proxy_transfer_mode */ + curl_function, /* 167 seekfunction */ + curl_string, /* 168 seekdata */ + curl_string, /* 169 crlfile */ + curl_string, /* 170 issuercert */ + curl_integer, /* 171 address_scope */ + curl_integer, /* 172 certinfo */ + curl_string, /* 173 username */ + curl_string, /* 174 password */ + curl_string, /* 175 proxyusername */ + curl_string, /* 176 proxypassword */ + curl_string, /* 177 noproxy */ + curl_integer, /* 178 tftp_blksize */ + curl_string, /* 179 socks5_gssapi_service */ + curl_integer, /* 180 socks5_gssapi_nec */ + curl_integer, /* 181 protocols */ + curl_integer, /* 182 redir_protocols */ + curl_string, /* 183 ssh_knownhosts */ + curl_function, /* 184 ssh_keyfunction */ + curl_string, /* 185 ssh_keydata */ + curl_string, /* 186 mail_from */ + curl_string, /* 187 mail_rcpt */ + curl_integer, /* 188 ftp_use_pret */ + curl_integer, /* 189 rtsp_request */ + curl_string, /* 190 rtsp_session_id */ + curl_string, /* 191 rtsp_stream_uri */ + curl_string, /* 192 rtsp_transport */ + curl_integer, /* 193 rtsp_client_cseq */ + curl_integer, /* 194 rtsp_server_cseq */ + curl_string, /* 195 interleavedata */ + curl_function, /* 196 interleavefunction */ + curl_integer, /* 197 wildcardmatch */ + curl_function, /* 198 chunk_bgn_function */ + curl_function, /* 199 chunk_end_function */ + curl_function, /* 200 fnmatch_function */ + curl_string, /* 201 chunk_data */ + curl_string, /* 202 fnmatch_data */ + curl_string, /* 203 resolve */ + curl_string, /* 204 tlsauth_username */ + curl_string, /* 205 tlsauth_password */ + curl_string, /* 206 tlsauth_type */ + curl_integer, /* 207 transfer_encoding */ + curl_function, /* 208 closesocketfunction */ + curl_string, /* 209 closesocketdata */ + curl_integer, /* 210 gssapi_delegation */ + curl_string, /* 211 dns_servers */ + curl_integer, /* 212 accepttimeout_ms */ + curl_integer, /* 213 tcp_keepalive */ + curl_integer, /* 214 tcp_keepidle */ + curl_integer, /* 215 tcp_keepintvl */ + curl_integer, /* 216 ssl_options */ + curl_string, /* 217 mail_auth */ + curl_integer, /* 218 sasl_ir */ + curl_function, /* 219 xferinfofunction */ + curl_string, /* 220 xoauth2_bearer */ + curl_string, /* 221 dns_interface */ + curl_string, /* 222 dns_local_ip4 */ + curl_string, /* 223 dns_local_ip6 */ + curl_string, /* 224 login_options */ + curl_integer, /* 225 ssl_enable_npn */ + curl_integer, /* 226 ssl_enable_alpn */ + curl_integer /* 227 expect_100_timeout_ms */ +}; + +# define curl_option_min 1 +# define curl_option_max 227 +# define curl_option_writedata 1 +# define curl_option_url 2 +# define curl_option_writefunction 11 + +# define curl_integer_base 0 /* long */ +# define curl_string_base 10000 +# define curl_object_base 10000 +# define curl_function_base 20000 +# define curl_offset_base 30000 +# define curl_offset_blob 40000 + +typedef size_t (*curl_write_callback) ( + char *buffer, + size_t size, + size_t nitems, + void *userdata +); + +typedef struct curllib_state_info { + + int initialized; + int padding; + + char * (*curl_version) ( + void + ); + + void (*curl_free) ( + void* p + ); + + curl_instance (*curl_easy_init) ( + void + ); + + void (*curl_easy_cleanup) ( + curl_instance handle + ); + + curl_return_code (*curl_easy_perform) ( + curl_instance handle + ); + + curl_return_code (*curl_easy_setopt) ( + curl_instance handle, + int option, + ... + ); + + char* (*curl_easy_escape) ( + curl_instance handle, + const char *url, + int length + ); + + char* (*curl_easy_unescape) ( + curl_instance handle, + const char *url, + int length, + int *outlength + ); + + const char* (*curl_easy_strerror) ( + curl_error_code errcode + ); + +} curllib_state_info; + +static curllib_state_info curllib_state = { + + .initialized = 0, + .padding = 0, + + .curl_version = NULL, + .curl_free = NULL, + .curl_easy_init = NULL, + .curl_easy_cleanup = NULL, + .curl_easy_perform = NULL, + .curl_easy_setopt = NULL, + .curl_easy_escape = NULL, + .curl_easy_unescape = NULL, + .curl_easy_strerror = NULL, + +}; + +static int curllib_initialize(lua_State * L) +{ + if (! curllib_state.initialized) { + const char *filename = lua_tostring(L, 1); + if (filename) { + + lmt_library lib = lmt_library_load(filename); + + curllib_state.curl_version = lmt_library_find(lib, "curl_version"); + curllib_state.curl_free = lmt_library_find(lib, "curl_free"); + curllib_state.curl_easy_init = lmt_library_find(lib, "curl_easy_init"); + curllib_state.curl_easy_cleanup = lmt_library_find(lib, "curl_easy_cleanup"); + curllib_state.curl_easy_perform = lmt_library_find(lib, "curl_easy_perform"); + curllib_state.curl_easy_setopt = lmt_library_find(lib, "curl_easy_setopt"); + curllib_state.curl_easy_escape = lmt_library_find(lib, "curl_easy_escape"); + curllib_state.curl_easy_unescape = lmt_library_find(lib, "curl_easy_unescape"); + curllib_state.curl_easy_strerror = lmt_library_find(lib, "curl_easy_strerror"); + + curllib_state.initialized = lmt_library_okay(lib); + } + } + lua_pushboolean(L, curllib_state.initialized); + return 1; +} + +/* fetch(url, { options }) | fetch({ options }) */ + +/* we don't need threads so we can just use the local init */ + +static size_t curllib_write_cb(char *data, size_t n, size_t l, void *b) +{ + luaL_addlstring((luaL_Buffer *) b, data, n * l); + return n * l; +} + +/*tex + Always assume a table as we need to sanitize keys anyway. A former variant also accepted strings + but why have more code than needed. +*/ + +static int curllib_fetch(lua_State * L) +{ + if (curllib_state.initialized) { + if (lua_type(L,1) == LUA_TTABLE) { + curl_instance *curl = curllib_state.curl_easy_init(); + if (curl) { + luaL_Buffer buffer; + luaL_buffinit(L, &buffer); + curllib_state.curl_easy_setopt(curl, curl_object_base + curl_option_writedata, &buffer); + curllib_state.curl_easy_setopt(curl, curl_function_base + curl_option_writefunction, &curllib_write_cb); + lua_pushnil(L); /* first key */ + while (lua_next(L, 1) != 0) { + if (lua_type(L, -2) == LUA_TNUMBER) { + int o = lmt_tointeger(L, -2); + if (o >= curl_option_min && o <= curl_option_max) { + switch (curl_options[o]) { + case curl_string: + if (lua_type(L, -1) == LUA_TSTRING) { + curllib_state.curl_easy_setopt(curl, curl_string_base + o, lua_tostring(L, -1)); + } else { + // return luaL_error(L, "curl option %d must be a string", o); + } + break; + case curl_integer: + switch (lua_type(L, -1)) { + case LUA_TNUMBER: + curllib_state.curl_easy_setopt(curl, curl_integer_base + o, lua_tointeger(L, -1)); + break; + case LUA_TBOOLEAN: + curllib_state.curl_easy_setopt(curl, curl_integer_base + o, lua_toboolean(L, -1)); + break; + default: + // return luaL_error(L, "curl option %d must be a number of boolean", o); + break; + } + break; + } + } else { + // return luaL_error(L, "curl option %d is invalid", o); + } + } else { + // return luaL_error(L, "curl option id should en a number"); + } + lua_pop(L, 1); /* removes 'value' and keeps 'key' for next iteration */ + } + int result = curllib_state.curl_easy_perform(curl); + if (result) { + lua_pushboolean(L, 0); + lua_pushstring(L, curllib_state.curl_easy_strerror(result)); + result = 2; + } else { + luaL_pushresult(&buffer); + result = 1; + } + curllib_state.curl_easy_cleanup(curl); + return result; + } + } + } + return 0; +} + +static int curllib_escape(lua_State * L) +{ + if (curllib_state.initialized) { + curl_instance *curl = curllib_state.curl_easy_init(); + if (curl) { + size_t length = 0; + const char * url = lua_tolstring(L, 1, &length); + char *s = curllib_state.curl_easy_escape(curl, url, (int) length); + if (s) { + lua_pushstring(L,(const char *) s); + curllib_state.curl_free(s); + curllib_state.curl_easy_cleanup(curl); + return 1; + } + } + } + return 0; +} + +static int curllib_unescape(lua_State * L) +{ + if (curllib_state.initialized) { + curl_instance *curl = curllib_state.curl_easy_init(); + if (curl) { + size_t length = 0; + const char *url = lua_tolstring(L, 1, &length); + int l = 0; + char *s = curllib_state.curl_easy_unescape(curl, url, (int) length, &l); + if (s) { + lua_pushlstring(L, s, l); + curllib_state.curl_free(s); + curllib_state.curl_easy_cleanup(curl); + return 1; + } + } + } + return 0; +} + +static int curllib_getversion(lua_State * L) +{ + if (curllib_state.initialized) { + char *version = curllib_state.curl_version(); + if (version) { + lua_pushstring(L, version); + return 1; + } + } + return 0; +} + +static struct luaL_Reg curllib_function_list[] = { + { "initialize", curllib_initialize }, + { "fetch", curllib_fetch }, + { "escape", curllib_escape }, + { "unescape", curllib_unescape }, + { "getversion", curllib_getversion }, + { NULL, NULL }, +}; + +int luaopen_curl(lua_State * L) +{ + lmt_library_register(L, "curl", curllib_function_list); + return 0; +} |