/* * SPL - The SPL Programming Language * Copyright (C) 2006 Clifford Wolf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * mod_curl.c: libcurl binding */ /** * cURL Module * * This module adds an interface to the cURL library. * * WARNING: This module is still under construction. */ #include #include "spl.h" #include "compat.h" extern void SPL_ABI(spl_mod_curl_init)(struct spl_vm *vm, struct spl_module *mod, int restore); extern void SPL_ABI(spl_mod_curl_done)(struct spl_vm *vm, struct spl_module *mod); struct my_curl_append_to_spl_string_arg { struct spl_string **data_ptr; char *encoding; }; static size_t my_curl_append_to_spl_string(void *ptr, size_t size, size_t nmemb, void *stream) { struct spl_string **data_ptr = ((struct my_curl_append_to_spl_string_arg*)stream)->data_ptr; char *encoding = ((struct my_curl_append_to_spl_string_arg*)stream)->encoding; struct spl_string *old_data = *data_ptr; char *string_raw = my_strndup(ptr, size*nmemb); char *string_encoded = string_raw; if (*encoding) { string_encoded = spl_utf8_import(string_raw, encoding); } else { if (spl_utf8_check(string_raw)) string_encoded = spl_utf8_import(string_raw, "ascii"); } *data_ptr = spl_string_new(0, old_data, 0, string_encoded, 0); if (string_encoded != string_raw) free(string_raw); spl_string_put(old_data); return size*nmemb; } #define MY_INT 1 #define MY_STR 2 static void my_curl_opt(CURL *c, struct spl_task *task, struct spl_node *options, int type, CURLoption opt, char *optname) { char lower_optname[strlen(optname)+1]; strcpy(lower_optname, optname); for (int i=0; lower_optname[i]; i++) if (lower_optname[i] >= 'A' && lower_optname[i] <= 'Z') lower_optname[i] += 'a' - 'A'; struct spl_node *option = spl_lookup(task, options, lower_optname, SPL_LOOKUP_TEST); if (!option) return; switch (type) { case MY_INT: curl_easy_setopt(c, opt, spl_get_int(option)); break; case MY_STR: curl_easy_setopt(c, opt, spl_get_string(option)); break; } } /** * Perform a cURL file transfer * * The first argument to this function is the URL. All other arguments * (cURL options) must be specified by name (lowercase and without the * CURLOPT_ prefix). A full list of cURL options can be found at: * * http://curl.haxx.se/libcurl/c/curl_easy_setopt.html * * The special argument 'encoding: ...' can be used to specify the expected * encoding of the data to be recieved. * * The return value is a data structure with the following fields: * * .header * The HTTP response header * * .body * The actual HTTP response * * Example given: * * var result = curl("http://de.wikipedia.org/wiki/Spezial:Search?", * post: 1, postfields: "search=SPL_Programming_Language"); * debug result.header; * */ //builtin curl(url, %options); static struct spl_node *handler_curl(struct spl_task *task, void UNUSED(*d)) { CURL *c = curl_easy_init(); CURLcode crc; char *url = spl_clib_get_string(task); if (url) curl_easy_setopt(c, CURLOPT_URL, url); struct spl_node *options = spl_clib_get_hargs(task); char *encoding = spl_get_string(spl_cleanup(task, spl_lookup(task, options, "encoding", SPL_LOOKUP_TEST))); struct spl_node *data = 0; struct spl_string *data_header = 0; struct spl_string *data_body = 0; struct my_curl_append_to_spl_string_arg data_header_arg = { .data_ptr = &data_header, .encoding = encoding }; curl_easy_setopt(c, CURLOPT_HEADERFUNCTION, my_curl_append_to_spl_string); curl_easy_setopt(c, CURLOPT_HEADERDATA, &data_header_arg); struct my_curl_append_to_spl_string_arg data_body_arg = { .data_ptr = &data_body, .encoding = encoding }; curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, my_curl_append_to_spl_string); curl_easy_setopt(c, CURLOPT_WRITEDATA, &data_body_arg); #define MYOPT(type, name) \ my_curl_opt(c, task, options, MY_ ## type, CURLOPT_ ## name, #name); /* NETWORK OPTIONS */ MYOPT(STR, URL); MYOPT(STR, PROXY); MYOPT(INT, PROXYPORT); // MYOPT(ENM, PROXYTYPE); MYOPT(INT, HTTPPROXYTUNNEL); MYOPT(STR, INTERFACE); MYOPT(INT, PORT); MYOPT(INT, TCP_NODELAY); /* NAMES and PASSWORDS OPTIONS */ // MYOPT(ENM, NETRC); // MYOPT(STR, NETRC_FILE); MYOPT(STR, USERPWD); MYOPT(STR, PROXYUSERPWD); // MYOPT(BFL, HTTPAUTH); // MYOPT(BFL, PROXYAUTH); /* HTTP OPTIONS */ MYOPT(INT, AUTOREFERER); MYOPT(STR, ENCODING); MYOPT(INT, FOLLOWLOCATION); MYOPT(INT, UNRESTRICTED_AUTH); MYOPT(INT, MAXREDIRS); MYOPT(INT, POST); MYOPT(STR, POSTFIELDS); MYOPT(INT, HTTPPOST); MYOPT(STR, REFERER); MYOPT(STR, USERAGENT); // MYOPT(LST, HTTPHEADER); // MYOPT(LST, HTTP200ALIASES); MYOPT(STR, COOKIE); MYOPT(STR, COOKIEFILE); MYOPT(STR, COOKIEJAR); MYOPT(INT, HTTPGET); // MYOPT(ENM, HTTP_VERSION); /* FTP OPTIONS */ MYOPT(INT, FTPPORT); // MYOPT(LST, QUOTE); // MYOPT(LST, POSTQUOTE); // MYOPT(LST, PREQUOTE); MYOPT(INT, FTPLISTONLY); MYOPT(INT, FTPAPPEND); MYOPT(INT, FTP_USE_EPRT); MYOPT(INT, FTP_USE_EPSV); MYOPT(INT, FTP_CREATE_MISSING_DIRS); MYOPT(INT, FTP_RESPONSE_TIMEOUT); // MYOPT(INT, FTP_SKIP_PASV_IP); // MYOPT(ENM, FTP_SSL); // MYOPT(ENM, FTPSSLAUTH); // MYOPT(STR, SOURCE_URL); // MYOPT(STR, SOURCE_USERPWD); // MYOPT(LST, SOURCE_QUOTE); // MYOPT(LST, SOURCE_PREQUOTE); // MYOPT(LST, SOURCE_POSTQUOTE); MYOPT(STR, FTP_ACCOUNT); /* PROTOCOL OPTIONS */ MYOPT(INT, TRANSFERTEXT); MYOPT(INT, CRLF); MYOPT(STR, RANGE); MYOPT(INT, RESUME_FROM); MYOPT(STR, CUSTOMREQUEST); MYOPT(INT, FILETIME); MYOPT(INT, NOBODY); MYOPT(INT, MAXFILESIZE); // MYOPT(ENM, TIMECONDITION); MYOPT(INT, TIMEVALUE); /* CONNECTION OPTIONS */ MYOPT(INT, TIMEOUT); MYOPT(INT, LOW_SPEED_LIMIT); MYOPT(INT, LOW_SPEED_TIME); MYOPT(INT, MAXCONNECTS); // MYOPT(ENM, CLOSEPOLICY); MYOPT(INT, FRESH_CONNECT); MYOPT(INT, FORBID_REUSE); MYOPT(INT, CONNECTTIMEOUT); // MYOPT(ENM, IPRESOLVE); /* SSL and SECURITY OPTIONS */ MYOPT(STR, SSLCERT); MYOPT(STR, SSLCERTTYPE); MYOPT(STR, SSLCERTPASSWD); MYOPT(STR, SSLKEY); MYOPT(STR, SSLKEYTYPE); MYOPT(STR, SSLKEYPASSWD); MYOPT(STR, SSLENGINE); MYOPT(STR, SSLENGINE_DEFAULT); // MYOPT(ENM, SSLVERSION); MYOPT(INT, SSL_VERIFYPEER); MYOPT(STR, CAINFO); MYOPT(STR, CAPATH); MYOPT(STR, RANDOM_FILE); MYOPT(STR, EGDSOCKET); MYOPT(INT, SSL_VERIFYHOST); MYOPT(STR, SSL_CIPHER_LIST); MYOPT(STR, KRB4LEVEL); /* END OF OPTIONS */ spl_put(task->vm, options); crc = curl_easy_perform(c); if (crc) { spl_clib_exception(task, "CurlEx", "description", SPL_NEW_PRINTF("cURL Error %d: %s", crc, curl_easy_strerror(crc)), "curlcode", SPL_NEW_INT(crc), NULL); goto cleanup; } data = spl_get(0); spl_create(task, data, "header", SPL_NEW_SPL_STRING(data_header), SPL_CREATE_LOCAL); spl_create(task, data, "body", SPL_NEW_SPL_STRING(data_body), SPL_CREATE_LOCAL); data_header = data_body = 0; cleanup: spl_string_put(data_header); spl_string_put(data_body); curl_easy_cleanup(c); return data; } static int curl_load_unload_counter = 0; void SPL_ABI(spl_mod_curl_init)(struct spl_vm *vm, struct spl_module *mod, int restore) { if (!restore) { spl_eval(vm, 0, strdup(mod->name), "object CurlEx { }"); } spl_clib_reg(vm, "curl", handler_curl, 0); curl_load_unload_counter++; } void SPL_ABI(spl_mod_curl_done)(struct spl_vm UNUSED(*vm), struct spl_module UNUSED(*mod)) { if (!--curl_load_unload_counter) curl_global_cleanup(); return; }