Asterisk - The Open Source Telephony Project GIT-master-754dea3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
Data Structures | Macros | Enumerations | Functions | Variables
func_curl.c File Reference

Curl - Load a URL. More...

#include "asterisk.h"
#include <curl/curl.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/cli.h"
#include "asterisk/module.h"
#include "asterisk/app.h"
#include "asterisk/utils.h"
#include "asterisk/threadstorage.h"
#include "asterisk/test.h"
Include dependency graph for func_curl.c:

Go to the source code of this file.

Data Structures

struct  curl_args
 
struct  curl_settings
 
struct  curl_write_callback_data
 Callback data passed to WriteMemoryCallback. More...
 
struct  global_curl_info
 

Macros

#define CURLOPT_SPECIAL_FAILURE_CODE   999
 
#define CURLOPT_SPECIAL_HASHCOMPAT   ((CURLoption) -500)
 
#define CURLVERSION_ATLEAST(a, b, c)    ((LIBCURL_VERSION_MAJOR > (a)) || ((LIBCURL_VERSION_MAJOR == (a)) && (LIBCURL_VERSION_MINOR > (b))) || ((LIBCURL_VERSION_MAJOR == (a)) && (LIBCURL_VERSION_MINOR == (b)) && (LIBCURL_VERSION_PATCH >= (c))))
 

Enumerations

enum  hashcompat { HASHCOMPAT_NO = 0 , HASHCOMPAT_YES , HASHCOMPAT_LEGACY }
 
enum  optiontype {
  OT_BOOLEAN , OT_INTEGER , OT_INTEGER_MS , OT_STRING ,
  OT_ENUM
}
 

Functions

static void __init_curl_instance (void)
 
static void __init_thread_escapebuf (void)
 
static void __reg_module (void)
 
static void __unreg_module (void)
 
static int acf_curl_exec (struct ast_channel *chan, const char *cmd, char *info, struct ast_str **buf, ssize_t len)
 
static int acf_curl_helper (struct ast_channel *chan, struct curl_args *args)
 
static int acf_curl_write (struct ast_channel *chan, const char *cmd, char *name, const char *value)
 
static int acf_curlopt_helper (struct ast_channel *chan, const char *cmd, char *data, char *buf, struct ast_str **bufstr, ssize_t len)
 
static int acf_curlopt_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 
static int acf_curlopt_read2 (struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
 
static int acf_curlopt_write (struct ast_channel *chan, const char *cmd, char *name, const char *value)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static void curl_instance_cleanup (void *data)
 
static int curl_instance_init (void *data)
 
static void curlds_free (void *data)
 
static int load_module (void)
 
static int parse_curlopt_key (const char *name, CURLoption *key, enum optiontype *ot)
 
static int unload_module (void)
 
static int url_is_vulnerable (const char *url)
 Check for potential HTTP injection risk. More...
 
static size_t WriteMemoryCallback (void *ptr, size_t size, size_t nmemb, void *data)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Load external URL" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_REALTIME_DEPEND2, .requires = "res_curl", }
 
static struct ast_custom_function acf_curl
 
static struct ast_custom_function acf_curlopt
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static const struct ast_datastore_info curl_info
 
static struct ast_threadstorage curl_instance = { .once = PTHREAD_ONCE_INIT , .key_init = __init_curl_instance , .custom_init = curl_instance_init , }
 
struct global_curl_info global_curl_info = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} } , }
 
static struct ast_threadstorage thread_escapebuf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_thread_escapebuf , .custom_init = NULL , }
 

Detailed Description

Curl - Load a URL.

Author
Tilghman Lesher curl-.nosp@m.2005.nosp@m.0919@.nosp@m.the-.nosp@m.tilgh.nosp@m.man..nosp@m.com
Note
Brian Wilkins bwilk.nosp@m.ins@.nosp@m.cfl.r.nosp@m.r.co.nosp@m.m (Added POST option)
ExtRef:
Depends on the CURL library - http://curl.haxx.se/

Definition in file func_curl.c.

Macro Definition Documentation

◆ CURLOPT_SPECIAL_FAILURE_CODE

#define CURLOPT_SPECIAL_FAILURE_CODE   999

Definition at line 258 of file func_curl.c.

◆ CURLOPT_SPECIAL_HASHCOMPAT

#define CURLOPT_SPECIAL_HASHCOMPAT   ((CURLoption) -500)

Definition at line 256 of file func_curl.c.

◆ CURLVERSION_ATLEAST

#define CURLVERSION_ATLEAST (   a,
  b,
  c 
)     ((LIBCURL_VERSION_MAJOR > (a)) || ((LIBCURL_VERSION_MAJOR == (a)) && (LIBCURL_VERSION_MINOR > (b))) || ((LIBCURL_VERSION_MAJOR == (a)) && (LIBCURL_VERSION_MINOR == (b)) && (LIBCURL_VERSION_PATCH >= (c))))

Definition at line 253 of file func_curl.c.

Enumeration Type Documentation

◆ hashcompat

enum hashcompat
Enumerator
HASHCOMPAT_NO 
HASHCOMPAT_YES 
HASHCOMPAT_LEGACY 

Definition at line 297 of file func_curl.c.

297 {
298 HASHCOMPAT_NO = 0,
301};
@ HASHCOMPAT_NO
Definition: func_curl.c:298
@ HASHCOMPAT_LEGACY
Definition: func_curl.c:300
@ HASHCOMPAT_YES
Definition: func_curl.c:299

◆ optiontype

enum optiontype
Enumerator
OT_BOOLEAN 
OT_INTEGER 
OT_INTEGER_MS 
OT_STRING 
OT_ENUM 

Definition at line 289 of file func_curl.c.

289 {
293 OT_STRING,
294 OT_ENUM,
295};
@ OT_BOOLEAN
Definition: func_curl.c:290
@ OT_ENUM
Definition: func_curl.c:294
@ OT_STRING
Definition: func_curl.c:293
@ OT_INTEGER
Definition: func_curl.c:291
@ OT_INTEGER_MS
Definition: func_curl.c:292

Function Documentation

◆ __init_curl_instance()

static void __init_curl_instance ( void  )
static

Definition at line 709 of file func_curl.c.

729{

◆ __init_thread_escapebuf()

static void __init_thread_escapebuf ( void  )
static

Definition at line 710 of file func_curl.c.

729{

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 1066 of file func_curl.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1066 of file func_curl.c.

◆ acf_curl_exec()

static int acf_curl_exec ( struct ast_channel chan,
const char *  cmd,
char *  info,
struct ast_str **  buf,
ssize_t  len 
)
static

Definition at line 904 of file func_curl.c.

905{
906 struct curl_args curl_params = { 0, };
907 int res;
908
912 );
913
915
916 if (ast_strlen_zero(info)) {
917 ast_log(LOG_WARNING, "CURL requires an argument (URL)\n");
918 return -1;
919 }
920
921 curl_params.url = args.url;
922 curl_params.postdata = args.postdata;
923 curl_params.cb_data.str = ast_str_create(16);
924 if (!curl_params.cb_data.str) {
925 return -1;
926 }
927
928 res = acf_curl_helper(chan, &curl_params);
929 ast_str_set(buf, len, "%s", ast_str_buffer(curl_params.cb_data.str));
930 ast_free(curl_params.cb_data.str);
931
932 return res;
933}
#define ast_free(a)
Definition: astmm.h:180
#define ast_log
Definition: astobj2.c:42
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int acf_curl_helper(struct ast_channel *chan, struct curl_args *args)
Definition: func_curl.c:743
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define LOG_WARNING
def info(msg)
static char url[512]
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
const char * postdata
Definition: func_curl.c:739
struct curl_write_callback_data cb_data
Definition: func_curl.c:740
const char * url
Definition: func_curl.c:738
struct ast_str * str
If a string is being built, the string buffer.
Definition: func_curl.c:663
const char * args

References acf_curl_helper(), args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_free, ast_log, AST_STANDARD_APP_ARGS, ast_str_buffer(), ast_str_create, ast_str_set(), ast_strlen_zero(), buf, curl_args::cb_data, sip_to_pjsip::info(), len(), LOG_WARNING, curl_args::postdata, curl_write_callback_data::str, curl_args::url, and url.

◆ acf_curl_helper()

static int acf_curl_helper ( struct ast_channel chan,
struct curl_args args 
)
static

Definition at line 743 of file func_curl.c.

744{
745 struct ast_str *escapebuf = ast_str_thread_get(&thread_escapebuf, 16);
746 int ret = 0;
747 long http_code = 0; /* read curl response */
748 size_t i;
749 struct ast_vector_int hasfailurecode = { NULL };
750 char *failurecodestrings,*found;
751 CURL **curl;
752 struct curl_settings *cur;
753 struct curl_slist *headers = NULL;
754 struct ast_datastore *store = NULL;
755 int hashcompat = 0;
757 char curl_errbuf[CURL_ERROR_SIZE + 1]; /* add one to be safe */
758
759 if (!escapebuf) {
760 return -1;
761 }
762
763 if (!(curl = ast_threadstorage_get(&curl_instance, sizeof(*curl)))) {
764 ast_log(LOG_ERROR, "Cannot allocate curl structure\n");
765 return -1;
766 }
767
768 if (url_is_vulnerable(args->url)) {
769 ast_log(LOG_ERROR, "URL '%s' is vulnerable to HTTP injection attacks. Aborting CURL() call.\n", args->url);
770 return -1;
771 }
772
773 if (chan) {
775 }
776
777 AST_VECTOR_INIT(&hasfailurecode, 0); /*Initialize vector*/
780 if (cur->key == CURLOPT_SPECIAL_HASHCOMPAT) {
781 hashcompat = (long) cur->value;
782 } else if (cur->key == CURLOPT_HTTPHEADER) {
783 headers = curl_slist_append(headers, (char*) cur->value);
784 } else if (cur->key == CURLOPT_SPECIAL_FAILURE_CODE) {
785 failurecodestrings = (char*) cur->value;
786 while( (found = strsep(&failurecodestrings, ",")) != NULL) {
787 AST_VECTOR_APPEND(&hasfailurecode, atoi(found));
788 }
789 } else {
790 curl_easy_setopt(*curl, cur->key, cur->value);
791 }
792 }
794
795 if (chan) {
796 ast_channel_lock(chan);
798 ast_channel_unlock(chan);
799 if (store) {
800 list = store->data;
801 AST_LIST_LOCK(list);
802 AST_LIST_TRAVERSE(list, cur, list) {
803 if (cur->key == CURLOPT_SPECIAL_HASHCOMPAT) {
804 hashcompat = (long) cur->value;
805 } else if (cur->key == CURLOPT_HTTPHEADER) {
806 headers = curl_slist_append(headers, (char*) cur->value);
807 } else if (cur->key == CURLOPT_SPECIAL_FAILURE_CODE) {
808 failurecodestrings = (char*) cur->value;
809 while( (found = strsep(&failurecodestrings, ",")) != NULL) {
810 AST_VECTOR_APPEND(&hasfailurecode, atoi(found));
811 }
812 } else {
813 curl_easy_setopt(*curl, cur->key, cur->value);
814 }
815 }
816 }
817 }
818
819 curl_easy_setopt(*curl, CURLOPT_URL, args->url);
820 curl_easy_setopt(*curl, CURLOPT_FILE, (void *) &args->cb_data);
821
822 if (args->postdata) {
823 curl_easy_setopt(*curl, CURLOPT_POST, 1);
824 curl_easy_setopt(*curl, CURLOPT_POSTFIELDS, args->postdata);
825 }
826
827 /* Always assign the headers - even when NULL - in case we had
828 * custom headers the last time we used this shared cURL
829 * instance */
830 curl_easy_setopt(*curl, CURLOPT_HTTPHEADER, headers);
831
832 /* Temporarily assign a buffer for curl to write errors to. */
833 curl_errbuf[0] = curl_errbuf[CURL_ERROR_SIZE] = '\0';
834 curl_easy_setopt(*curl, CURLOPT_ERRORBUFFER, curl_errbuf);
835
836 if (curl_easy_perform(*curl) != 0) {
837 ast_log(LOG_WARNING, "%s ('%s')\n", curl_errbuf, args->url);
838 }
839
840 /* Reset buffer to NULL so curl doesn't try to write to it when the
841 * buffer is deallocated. Documentation is vague about allowing NULL
842 * here, but the source allows it. See: "typecheck: allow NULL to unset
843 * CURLOPT_ERRORBUFFER" (62bcf005f4678a93158358265ba905bace33b834). */
844 curl_easy_setopt(*curl, CURLOPT_ERRORBUFFER, (char*)NULL);
845 curl_easy_getinfo (*curl, CURLINFO_RESPONSE_CODE, &http_code);
846
847 for (i = 0; i < AST_VECTOR_SIZE(&hasfailurecode); ++i) {
848 if (http_code == AST_VECTOR_GET(&hasfailurecode,i)){
849 ast_log(LOG_NOTICE, "%s%sCURL '%s' returned response code (%ld).\n",
850 chan ? ast_channel_name(chan) : "",
851 chan ? ast_channel_name(chan) : ": ",
852 args->url,
853 http_code);
854 ret=-1;
855 break;
856 }
857 }
858 AST_VECTOR_FREE(&hasfailurecode); /* Release the vector*/
859
860 if (store) {
861 AST_LIST_UNLOCK(list);
862 }
863 curl_slist_free_all(headers);
864
865 if (args->postdata) {
866 curl_easy_setopt(*curl, CURLOPT_POST, 0);
867 }
868
869 if (args->cb_data.str && ast_str_strlen(args->cb_data.str)) {
870 ast_str_trim_blanks(args->cb_data.str);
871
872 ast_debug(3, "CURL returned str='%s'\n", ast_str_buffer(args->cb_data.str));
873 if (hashcompat) {
874 char *remainder = ast_str_buffer(args->cb_data.str);
875 char *piece;
876 struct ast_str *fields = ast_str_create(ast_str_strlen(args->cb_data.str) / 2);
877 struct ast_str *values = ast_str_create(ast_str_strlen(args->cb_data.str) / 2);
878 int rowcount = 0;
879 while (fields && values && (piece = strsep(&remainder, "&"))) {
880 char *name = strsep(&piece, "=");
882 if (piece) {
883 ast_uri_decode(piece, mode);
884 }
885 ast_uri_decode(name, mode);
886 ast_str_append(&fields, 0, "%s%s", rowcount ? "," : "", ast_str_set_escapecommas(&escapebuf, 0, name, INT_MAX));
887 ast_str_append(&values, 0, "%s%s", rowcount ? "," : "", ast_str_set_escapecommas(&escapebuf, 0, S_OR(piece, ""), INT_MAX));
888 rowcount++;
889 }
890 pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", ast_str_buffer(fields));
891 ast_str_set(&args->cb_data.str, 0, "%s", ast_str_buffer(values));
892 ast_free(fields);
894 }
895 }
896
897 if (chan) {
899 }
900
901 return ret;
902}
char * strsep(char **str, const char *delims)
const char * ast_channel_name(const struct ast_channel *chan)
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
#define ast_channel_lock(chan)
Definition: channel.h:2970
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
#define ast_channel_unlock(chan)
Definition: channel.h:2971
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2428
static const char name[]
Definition: format_mp3.c:68
#define CURLOPT_SPECIAL_HASHCOMPAT
Definition: func_curl.c:256
static const struct ast_datastore_info curl_info
Definition: func_curl.c:262
#define CURLOPT_SPECIAL_FAILURE_CODE
Definition: func_curl.c:258
static struct ast_threadstorage thread_escapebuf
Definition: func_curl.c:710
static int url_is_vulnerable(const char *url)
Check for potential HTTP injection risk.
Definition: func_curl.c:728
static struct ast_threadstorage curl_instance
Definition: func_curl.c:709
hashcompat
Definition: func_curl.c:297
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_NOTICE
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: linkedlists.h:173
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
#define NULL
Definition: resample.c:96
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
char * ast_str_set_escapecommas(struct ast_str **buf, ssize_t maxlen, const char *src, size_t maxsrc)
Set a dynamic string to a non-NULL terminated substring, with escaping of commas.
Definition: strings.h:1069
void ast_str_trim_blanks(struct ast_str *buf)
Trims trailing whitespace characters from an ast_str string.
Definition: strings.h:719
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:730
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition: strings.h:909
Structure for a data store object.
Definition: datastore.h:64
void * data
Definition: datastore.h:66
Structure used to handle boolean flags.
Definition: utils.h:199
Support for dynamic strings.
Definition: strings.h:623
Integer vector definition.
Definition: vector.h:52
void * value
Definition: func_curl.c:270
CURLoption key
Definition: func_curl.c:269
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.
const struct ast_flags ast_uri_http
Definition: utils.c:719
void ast_uri_decode(char *s, struct ast_flags spec)
Decode URI, URN, URL (overwrite string)
Definition: utils.c:762
const struct ast_flags ast_uri_http_legacy
Definition: utils.c:720
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680

References args, ast_autoservice_start(), ast_autoservice_stop(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_debug, ast_free, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log, ast_str_append(), ast_str_buffer(), ast_str_create, ast_str_set(), ast_str_set_escapecommas(), ast_str_strlen(), ast_str_thread_get(), ast_str_trim_blanks(), ast_threadstorage_get(), ast_uri_decode(), ast_uri_http, ast_uri_http_legacy, AST_VECTOR_APPEND, AST_VECTOR_FREE, AST_VECTOR_GET, AST_VECTOR_INIT, AST_VECTOR_SIZE, curl_info, curl_instance, CURLOPT_SPECIAL_FAILURE_CODE, CURLOPT_SPECIAL_HASHCOMPAT, ast_datastore::data, HASHCOMPAT_LEGACY, curl_settings::key, LOG_ERROR, LOG_NOTICE, LOG_WARNING, name, NULL, pbx_builtin_setvar_helper(), S_OR, strsep(), thread_escapebuf, url_is_vulnerable(), and curl_settings::value.

Referenced by acf_curl_exec(), and acf_curl_write().

◆ acf_curl_write()

static int acf_curl_write ( struct ast_channel chan,
const char *  cmd,
char *  name,
const char *  value 
)
static

Definition at line 935 of file func_curl.c.

936{
937 struct curl_args curl_params = { 0, };
938 int res;
939 char *args_value = ast_strdupa(value);
941 AST_APP_ARG(file_path);
942 );
943
944 AST_STANDARD_APP_ARGS(args, args_value);
945
946 if (ast_strlen_zero(name)) {
947 ast_log(LOG_WARNING, "CURL requires an argument (URL)\n");
948 return -1;
949 }
950
951 if (ast_strlen_zero(args.file_path)) {
952 ast_log(LOG_WARNING, "CURL requires a file to write\n");
953 return -1;
954 }
955
956 curl_params.url = name;
957 curl_params.cb_data.out_file = fopen(args.file_path, "w");
958 if (!curl_params.cb_data.out_file) {
959 ast_log(LOG_WARNING, "Failed to open file %s: %s (%d)\n",
960 args.file_path,
961 strerror(errno),
962 errno);
963 return -1;
964 }
965
966 res = acf_curl_helper(chan, &curl_params);
967
968 fclose(curl_params.cb_data.out_file);
969
970 return res;
971}
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
int errno
FILE * out_file
If a file is being retrieved, the file to write to.
Definition: func_curl.c:667
int value
Definition: syslog.c:37

References acf_curl_helper(), args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), curl_args::cb_data, errno, LOG_WARNING, name, curl_write_callback_data::out_file, curl_args::url, and value.

◆ acf_curlopt_helper()

static int acf_curlopt_helper ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
struct ast_str **  bufstr,
ssize_t  len 
)
static

Definition at line 535 of file func_curl.c.

536{
537 struct ast_datastore *store;
538 struct global_curl_info *list[2] = { &global_curl_info, NULL };
539 struct curl_settings *cur = NULL;
540 CURLoption key;
541 enum optiontype ot;
542 int i;
543
544 if (parse_curlopt_key(data, &key, &ot)) {
545 ast_log(LOG_ERROR, "Unrecognized option: '%s'\n", data);
546 return -1;
547 }
548
549 if (chan) {
550 /* If we have a channel, we want to read the options set there before
551 falling back to the global settings */
552 ast_channel_lock(chan);
554 ast_channel_unlock(chan);
555
556 if (store) {
557 list[0] = store->data;
559 }
560 }
561
562 for (i = 0; i < 2; i++) {
563 if (!list[i]) {
564 break;
565 }
567 AST_LIST_TRAVERSE(list[i], cur, list) {
568 if (cur->key == key) {
569 if (ot == OT_BOOLEAN || ot == OT_INTEGER) {
570 if (buf) {
571 snprintf(buf, len, "%ld", (long) cur->value);
572 } else {
573 ast_str_set(bufstr, len, "%ld", (long) cur->value);
574 }
575 } else if (ot == OT_INTEGER_MS) {
576 if ((long) cur->value % 1000 == 0) {
577 if (buf) {
578 snprintf(buf, len, "%ld", (long)cur->value / 1000);
579 } else {
580 ast_str_set(bufstr, len, "%ld", (long) cur->value / 1000);
581 }
582 } else {
583 if (buf) {
584 snprintf(buf, len, "%.3f", (double) ((long) cur->value) / 1000.0);
585 } else {
586 ast_str_set(bufstr, len, "%.3f", (double) ((long) cur->value) / 1000.0);
587 }
588 }
589 } else if (ot == OT_STRING) {
590 ast_debug(1, "Found entry %p, with key %d and value %p\n", cur, cur->key, cur->value);
591 if (buf) {
593 } else {
594 ast_str_set(bufstr, 0, "%s", (char *) cur->value);
595 }
596 } else if (key == CURLOPT_PROXYTYPE) {
597 const char *strval = "unknown";
598 if (0) {
599#if CURLVERSION_ATLEAST(7,15,2)
600 } else if ((long)cur->value == CURLPROXY_SOCKS4) {
601 strval = "socks4";
602#endif
603#if CURLVERSION_ATLEAST(7,18,0)
604 } else if ((long)cur->value == CURLPROXY_SOCKS4A) {
605 strval = "socks4a";
606#endif
607 } else if ((long)cur->value == CURLPROXY_SOCKS5) {
608 strval = "socks5";
609#if CURLVERSION_ATLEAST(7,18,0)
610 } else if ((long)cur->value == CURLPROXY_SOCKS5_HOSTNAME) {
611 strval = "socks5hostname";
612#endif
613#if CURLVERSION_ATLEAST(7,10,0)
614 } else if ((long)cur->value == CURLPROXY_HTTP) {
615 strval = "http";
616#endif
617 }
618 if (buf) {
619 ast_copy_string(buf, strval, len);
620 } else {
621 ast_str_set(bufstr, 0, "%s", strval);
622 }
623 } else if (key == CURLOPT_SPECIAL_HASHCOMPAT) {
624 const char *strval = "unknown";
625 if ((long) cur->value == HASHCOMPAT_LEGACY) {
626 strval = "legacy";
627 } else if ((long) cur->value == HASHCOMPAT_YES) {
628 strval = "yes";
629 } else if ((long) cur->value == HASHCOMPAT_NO) {
630 strval = "no";
631 }
632 if (buf) {
633 ast_copy_string(buf, strval, len);
634 } else {
635 ast_str_set(bufstr, 0, "%s", strval);
636 }
637 }
638 break;
639 }
640 }
642 if (cur) {
643 break;
644 }
645 }
646
647 return cur ? 0 : -1;
648}
optiontype
Definition: func_curl.c:289
struct global_curl_info global_curl_info
static int parse_curlopt_key(const char *name, CURLoption *key, enum optiontype *ot)
Definition: func_curl.c:303
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
struct curl_settings::@168 list

References ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_debug, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log, ast_str_set(), buf, curl_info, CURLOPT_SPECIAL_HASHCOMPAT, ast_datastore::data, global_curl_info, HASHCOMPAT_LEGACY, HASHCOMPAT_NO, HASHCOMPAT_YES, curl_settings::key, len(), curl_settings::list, LOG_ERROR, NULL, OT_BOOLEAN, OT_INTEGER, OT_INTEGER_MS, OT_STRING, parse_curlopt_key(), and curl_settings::value.

Referenced by acf_curlopt_read(), and acf_curlopt_read2().

◆ acf_curlopt_read()

static int acf_curlopt_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
)
static

Definition at line 650 of file func_curl.c.

651{
652 return acf_curlopt_helper(chan, cmd, data, buf, NULL, len);
653}
static int acf_curlopt_helper(struct ast_channel *chan, const char *cmd, char *data, char *buf, struct ast_str **bufstr, ssize_t len)
Definition: func_curl.c:535

References acf_curlopt_helper(), buf, len(), and NULL.

◆ acf_curlopt_read2()

static int acf_curlopt_read2 ( struct ast_channel chan,
const char *  cmd,
char *  data,
struct ast_str **  buf,
ssize_t  len 
)
static

Definition at line 655 of file func_curl.c.

656{
657 return acf_curlopt_helper(chan, cmd, data, NULL, buf, len);
658}

References acf_curlopt_helper(), buf, len(), and NULL.

◆ acf_curlopt_write()

static int acf_curlopt_write ( struct ast_channel chan,
const char *  cmd,
char *  name,
const char *  value 
)
static

Definition at line 405 of file func_curl.c.

406{
407 struct ast_datastore *store;
408 struct global_curl_info *list;
409 struct curl_settings *cur, *new = NULL;
410 CURLoption key;
411 enum optiontype ot;
412
413 if (chan) {
414 ast_channel_lock(chan);
415 if (!(store = ast_channel_datastore_find(chan, &curl_info, NULL))) {
416 /* Create a new datastore */
417 if (!(store = ast_datastore_alloc(&curl_info, NULL))) {
418 ast_log(LOG_ERROR, "Unable to allocate new datastore. Cannot set any CURL options\n");
419 ast_channel_unlock(chan);
420 return -1;
421 }
422
423 if (!(list = ast_calloc(1, sizeof(*list)))) {
424 ast_log(LOG_ERROR, "Unable to allocate list head. Cannot set any CURL options\n");
425 ast_datastore_free(store);
426 ast_channel_unlock(chan);
427 return -1;
428 }
429
430 store->data = list;
432 ast_channel_datastore_add(chan, store);
433 } else {
434 list = store->data;
435 }
436 ast_channel_unlock(chan);
437 } else {
438 /* Populate the global structure */
440 }
441
442 if (!parse_curlopt_key(name, &key, &ot)) {
443 if (ot == OT_BOOLEAN) {
444 if ((new = ast_calloc(1, sizeof(*new)))) {
445 new->value = (void *)((long) ast_true(value));
446 }
447 } else if (ot == OT_INTEGER) {
448 long tmp = atol(value);
449 if ((new = ast_calloc(1, sizeof(*new)))) {
450 new->value = (void *)tmp;
451 }
452 } else if (ot == OT_INTEGER_MS) {
453 long tmp = atof(value) * 1000.0;
454 if ((new = ast_calloc(1, sizeof(*new)))) {
455 new->value = (void *)tmp;
456 }
457 } else if (ot == OT_STRING) {
458 if ((new = ast_calloc(1, sizeof(*new) + strlen(value) + 1))) {
459 new->value = (char *)new + sizeof(*new);
460 strcpy(new->value, value);
461 }
462 } else if (ot == OT_ENUM) {
463 if (key == CURLOPT_PROXYTYPE) {
464 long ptype =
465#if CURLVERSION_ATLEAST(7,10,0)
466 CURLPROXY_HTTP;
467#else
468 CURLPROXY_SOCKS5;
469#endif
470 if (0) {
471#if CURLVERSION_ATLEAST(7,15,2)
472 } else if (!strcasecmp(value, "socks4")) {
473 ptype = CURLPROXY_SOCKS4;
474#endif
475#if CURLVERSION_ATLEAST(7,18,0)
476 } else if (!strcasecmp(value, "socks4a")) {
477 ptype = CURLPROXY_SOCKS4A;
478#endif
479#if CURLVERSION_ATLEAST(7,18,0)
480 } else if (!strcasecmp(value, "socks5")) {
481 ptype = CURLPROXY_SOCKS5;
482#endif
483#if CURLVERSION_ATLEAST(7,18,0)
484 } else if (!strncasecmp(value, "socks5", 6)) {
485 ptype = CURLPROXY_SOCKS5_HOSTNAME;
486#endif
487 }
488
489 if ((new = ast_calloc(1, sizeof(*new)))) {
490 new->value = (void *)ptype;
491 }
492 } else if (key == CURLOPT_SPECIAL_HASHCOMPAT) {
493 if ((new = ast_calloc(1, sizeof(*new)))) {
494 new->value = (void *) (long) (!strcasecmp(value, "legacy") ? HASHCOMPAT_LEGACY : ast_true(value) ? HASHCOMPAT_YES : HASHCOMPAT_NO);
495 }
496 } else {
497 /* Highly unlikely */
498 goto yuck;
499 }
500 }
501
502 /* Memory allocation error */
503 if (!new) {
504 return -1;
505 }
506
507 new->key = key;
508 } else {
509yuck:
510 ast_log(LOG_ERROR, "Unrecognized option: %s\n", name);
511 return -1;
512 }
513
514 /* Remove any existing entry, only http headers are left */
516 if (new->key != CURLOPT_HTTPHEADER) {
518 if (cur->key == new->key) {
520 ast_free(cur);
521 break;
522 }
523 }
525 }
526
527 /* Insert new entry */
528 ast_debug(1, "Inserting entry %p with key %d and value %p\n", new, new->key, new->value);
531
532 return 0;
533}
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2414
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:85
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
Definition: linkedlists.h:626
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2199

References ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc, ast_datastore_free(), ast_debug, ast_free, AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log, ast_true(), curl_info, CURLOPT_SPECIAL_HASHCOMPAT, ast_datastore::data, global_curl_info, HASHCOMPAT_LEGACY, HASHCOMPAT_NO, HASHCOMPAT_YES, curl_settings::key, curl_settings::list, LOG_ERROR, name, NULL, OT_BOOLEAN, OT_ENUM, OT_INTEGER, OT_INTEGER_MS, OT_STRING, parse_curlopt_key(), and value.

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 1066 of file func_curl.c.

◆ curl_instance_cleanup()

static void curl_instance_cleanup ( void *  data)
static

Definition at line 700 of file func_curl.c.

701{
702 CURL **curl = data;
703
704 curl_easy_cleanup(*curl);
705
706 ast_free(data);
707}

References ast_free.

◆ curl_instance_init()

static int curl_instance_init ( void *  data)
static

Definition at line 685 of file func_curl.c.

686{
687 CURL **curl = data;
688
689 if (!(*curl = curl_easy_init()))
690 return -1;
691
692 curl_easy_setopt(*curl, CURLOPT_NOSIGNAL, 1);
693 curl_easy_setopt(*curl, CURLOPT_TIMEOUT, 180);
694 curl_easy_setopt(*curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
695 curl_easy_setopt(*curl, CURLOPT_USERAGENT, AST_CURL_USER_AGENT);
696
697 return 0;
698}
#define AST_CURL_USER_AGENT
Definition: asterisk.h:44
static size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
Definition: func_curl.c:670

References AST_CURL_USER_AGENT, and WriteMemoryCallback().

◆ curlds_free()

static void curlds_free ( void *  data)
static

Definition at line 275 of file func_curl.c.

276{
278 struct curl_settings *setting;
279 if (!list) {
280 return;
281 }
282 while ((setting = AST_LIST_REMOVE_HEAD(list, list))) {
283 ast_free(setting);
284 }
286 ast_free(list);
287}
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
Definition: linkedlists.h:653
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833

References ast_free, AST_LIST_HEAD, AST_LIST_HEAD_DESTROY, AST_LIST_REMOVE_HEAD, and curl_settings::list.

◆ load_module()

static int load_module ( void  )
static

Definition at line 1048 of file func_curl.c.

1049{
1050 int res;
1051
1054
1055 AST_TEST_REGISTER(vulnerable_url);
1056
1057 return res;
1058}
static struct ast_custom_function acf_curlopt
Definition: func_curl.c:979
static struct ast_custom_function acf_curl
Definition: func_curl.c:973
#define ast_custom_function_register_escalating(acf, escalation)
Register a custom function which requires escalated privileges.
Definition: pbx.h:1568
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1559
@ AST_CFE_WRITE
Definition: pbx.h:1552
#define AST_TEST_REGISTER(cb)
Definition: test.h:127

References acf_curl, acf_curlopt, AST_CFE_WRITE, ast_custom_function_register, ast_custom_function_register_escalating, and AST_TEST_REGISTER.

◆ parse_curlopt_key()

static int parse_curlopt_key ( const char *  name,
CURLoption *  key,
enum optiontype ot 
)
static

Definition at line 303 of file func_curl.c.

304{
305 if (!strcasecmp(name, "header")) {
306 *key = CURLOPT_HEADER;
307 *ot = OT_BOOLEAN;
308 } else if (!strcasecmp(name, "httpheader")) {
309 *key = CURLOPT_HTTPHEADER;
310 *ot = OT_STRING;
311 } else if (!strcasecmp(name, "proxy")) {
312 *key = CURLOPT_PROXY;
313 *ot = OT_STRING;
314 } else if (!strcasecmp(name, "proxyport")) {
315 *key = CURLOPT_PROXYPORT;
316 *ot = OT_INTEGER;
317 } else if (!strcasecmp(name, "proxytype")) {
318 *key = CURLOPT_PROXYTYPE;
319 *ot = OT_ENUM;
320 } else if (!strcasecmp(name, "dnstimeout")) {
321 *key = CURLOPT_DNS_CACHE_TIMEOUT;
322 *ot = OT_INTEGER;
323 } else if (!strcasecmp(name, "userpwd")) {
324 *key = CURLOPT_USERPWD;
325 *ot = OT_STRING;
326 } else if (!strcasecmp(name, "proxyuserpwd")) {
327 *key = CURLOPT_PROXYUSERPWD;
328 *ot = OT_STRING;
329 } else if (!strcasecmp(name, "followlocation")) {
330 *key = CURLOPT_FOLLOWLOCATION;
331 *ot = OT_BOOLEAN;
332 } else if (!strcasecmp(name, "maxredirs")) {
333 *key = CURLOPT_MAXREDIRS;
334 *ot = OT_INTEGER;
335 } else if (!strcasecmp(name, "referer")) {
336 *key = CURLOPT_REFERER;
337 *ot = OT_STRING;
338 } else if (!strcasecmp(name, "useragent")) {
339 *key = CURLOPT_USERAGENT;
340 *ot = OT_STRING;
341 } else if (!strcasecmp(name, "cookie")) {
342 *key = CURLOPT_COOKIE;
343 *ot = OT_STRING;
344 } else if (!strcasecmp(name, "ftptimeout")) {
345 *key = CURLOPT_FTP_RESPONSE_TIMEOUT;
346 *ot = OT_INTEGER;
347 } else if (!strcasecmp(name, "httptimeout")) {
348#if CURLVERSION_ATLEAST(7,16,2)
349 *key = CURLOPT_TIMEOUT_MS;
350 *ot = OT_INTEGER_MS;
351#else
352 *key = CURLOPT_TIMEOUT;
353 *ot = OT_INTEGER;
354#endif
355 } else if (!strcasecmp(name, "conntimeout")) {
356#if CURLVERSION_ATLEAST(7,16,2)
357 *key = CURLOPT_CONNECTTIMEOUT_MS;
358 *ot = OT_INTEGER_MS;
359#else
360 *key = CURLOPT_CONNECTTIMEOUT;
361 *ot = OT_INTEGER;
362#endif
363 } else if (!strcasecmp(name, "ftptext")) {
364 *key = CURLOPT_TRANSFERTEXT;
365 *ot = OT_BOOLEAN;
366 } else if (!strcasecmp(name, "ssl_verifypeer")) {
367 *key = CURLOPT_SSL_VERIFYPEER;
368 *ot = OT_BOOLEAN;
369 } else if (!strcasecmp(name, "ssl_verifyhost")) {
370 *key = CURLOPT_SSL_VERIFYHOST;
371 *ot = OT_INTEGER;
372 } else if (!strcasecmp(name, "ssl_cainfo")) {
373 *key = CURLOPT_CAINFO;
374 *ot = OT_STRING;
375 } else if (!strcasecmp(name, "ssl_capath")) {
376 *key = CURLOPT_CAPATH;
377 *ot = OT_STRING;
378 } else if (!strcasecmp(name, "ssl_cert")) {
379 *key = CURLOPT_SSLCERT;
380 *ot = OT_STRING;
381 } else if (!strcasecmp(name, "ssl_certtype")) {
382 *key = CURLOPT_SSLCERTTYPE;
383 *ot = OT_STRING;
384 } else if (!strcasecmp(name, "ssl_key")) {
385 *key = CURLOPT_SSLKEY;
386 *ot = OT_STRING;
387 } else if (!strcasecmp(name, "ssl_keytype")) {
388 *key = CURLOPT_SSLKEYTYPE;
389 *ot = OT_STRING;
390 } else if (!strcasecmp(name, "ssl_keypasswd")) {
391 *key = CURLOPT_KEYPASSWD;
392 *ot = OT_STRING;
393 } else if (!strcasecmp(name, "hashcompat")) {
395 *ot = OT_ENUM;
396 } else if (!strcasecmp(name, "failurecodes")) {
398 *ot = OT_STRING;
399 } else {
400 return -1;
401 }
402 return 0;
403}

References CURLOPT_SPECIAL_FAILURE_CODE, CURLOPT_SPECIAL_HASHCOMPAT, curl_settings::key, name, OT_BOOLEAN, OT_ENUM, OT_INTEGER, OT_INTEGER_MS, and OT_STRING.

Referenced by acf_curlopt_helper(), and acf_curlopt_write().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 1036 of file func_curl.c.

1037{
1038 int res;
1039
1042
1043 AST_TEST_UNREGISTER(vulnerable_url);
1044
1045 return res;
1046}
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128

References acf_curl, acf_curlopt, ast_custom_function_unregister(), and AST_TEST_UNREGISTER.

◆ url_is_vulnerable()

static int url_is_vulnerable ( const char *  url)
static

Check for potential HTTP injection risk.

CVE-2014-8150 brought up the fact that HTTP proxies are subject to injection attacks. An HTTP URL sent to a proxy contains a carriage-return linefeed combination, followed by a complete HTTP request. Proxies will handle this as two separate HTTP requests rather than as a malformed URL.

libcURL patched this vulnerability in version 7.40.0, but we have no guarantee that Asterisk systems will be using an up-to-date cURL library. Therefore, we implement the same fix as libcURL for determining if a URL is vulnerable to an injection attack.

Parameters
urlThe URL to check for vulnerability
Return values
0The URL is not vulnerable
1The URL is vulnerable.

Definition at line 728 of file func_curl.c.

729{
730 if (strpbrk(url, "\r\n")) {
731 return 1;
732 }
733
734 return 0;
735}

References url.

Referenced by acf_curl_helper().

◆ WriteMemoryCallback()

static size_t WriteMemoryCallback ( void *  ptr,
size_t  size,
size_t  nmemb,
void *  data 
)
static

Definition at line 670 of file func_curl.c.

671{
672 register int realsize = 0;
673 struct curl_write_callback_data *cb_data = data;
674
675 if (cb_data->str) {
676 realsize = size * nmemb;
677 ast_str_append_substr(&cb_data->str, 0, ptr, realsize);
678 } else if (cb_data->out_file) {
679 realsize = fwrite(ptr, size, nmemb, cb_data->out_file);
680 }
681
682 return realsize;
683}
char * ast_str_append_substr(struct ast_str **buf, ssize_t maxlen, const char *src, size_t maxsrc)
Append a non-NULL terminated substring to the end of a dynamic string.
Definition: strings.h:1062
Callback data passed to WriteMemoryCallback.
Definition: func_curl.c:661

References ast_str_append_substr(), curl_write_callback_data::out_file, and curl_write_callback_data::str.

Referenced by curl_instance_init().

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Load external URL" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_REALTIME_DEPEND2, .requires = "res_curl", }
static

Definition at line 1066 of file func_curl.c.

◆ acf_curl

struct ast_custom_function acf_curl
static
Initial value:
= {
.name = "CURL",
.read2 = acf_curl_exec,
.write = acf_curl_write,
}
static int acf_curl_exec(struct ast_channel *chan, const char *cmd, char *info, struct ast_str **buf, ssize_t len)
Definition: func_curl.c:904
static int acf_curl_write(struct ast_channel *chan, const char *cmd, char *name, const char *value)
Definition: func_curl.c:935

Definition at line 973 of file func_curl.c.

Referenced by load_module(), and unload_module().

◆ acf_curlopt

struct ast_custom_function acf_curlopt
static

Definition at line 979 of file func_curl.c.

Referenced by load_module(), and unload_module().

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 1066 of file func_curl.c.

◆ curl_info

const struct ast_datastore_info curl_info
static
Initial value:
= {
.type = "CURL",
.destroy = curlds_free,
}
static void curlds_free(void *data)
Definition: func_curl.c:275

Definition at line 262 of file func_curl.c.

Referenced by acf_curl_helper(), acf_curlopt_helper(), and acf_curlopt_write().

◆ curl_instance

struct ast_threadstorage curl_instance = { .once = PTHREAD_ONCE_INIT , .key_init = __init_curl_instance , .custom_init = curl_instance_init , }
static

Definition at line 709 of file func_curl.c.

Referenced by acf_curl_helper().

◆ global_curl_info

struct global_curl_info global_curl_info = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} } , }

◆ thread_escapebuf

struct ast_threadstorage thread_escapebuf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_thread_escapebuf , .custom_init = NULL , }
static

Definition at line 710 of file func_curl.c.

Referenced by acf_curl_helper().