From f032b8c1589071bc62d749d490b0dad6306e879b Mon Sep 17 00:00:00 2001 From: Martin Tomec Date: Thu, 7 Nov 2019 17:54:06 +0000 Subject: [PATCH] func_curl.c: Support custom http headers When user wants to send json data, the default Content-Type header is incorect (application/x-www-form-urlencoded). This patch allows to set any custom headers so the Content-Type header can be overriden. User can set multiple headers by multiple calls of curlopt(). This approach is not consistent with other parameters, but is more readable in dialplan than one call with multiple headers. ASTERISK-28613 Change-Id: I4dd68c3f4e25362ef941d73a3861f58348dcfbf9 --- doc/CHANGES-staging/func_curl_headers.txt | 6 ++++ funcs/func_curl.c | 37 ++++++++++++++++++----- 2 files changed, 35 insertions(+), 8 deletions(-) create mode 100644 doc/CHANGES-staging/func_curl_headers.txt diff --git a/doc/CHANGES-staging/func_curl_headers.txt b/doc/CHANGES-staging/func_curl_headers.txt new file mode 100644 index 0000000000..9d5c8c3e18 --- /dev/null +++ b/doc/CHANGES-staging/func_curl_headers.txt @@ -0,0 +1,6 @@ +Subject: func_curl + +A new parameter, httpheader, has been added to CURLOPT function. This parameter +allows to set custom http headers for subsequent calls off CURL function. +Any setting of headers will replace the default curl headers +(e.g. "Content-type: application/x-www-form-urlencoded") diff --git a/funcs/func_curl.c b/funcs/func_curl.c index 89a4688e7a..06a8b5354e 100644 --- a/funcs/func_curl.c +++ b/funcs/func_curl.c @@ -99,6 +99,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") Include header information in the result (boolean) + + Add HTTP header. Multiple calls add multiple headers. + Setting of any header will remove the default + "Content-Type application/x-www-form-urlencoded" + For HTTP(S) URIs, number of seconds to wait for a server response @@ -159,7 +164,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") Options may be set globally or per channel. Per-channel - settings will override global settings. + settings will override global settings. Only HTTP headers are added instead of overriding CURL @@ -221,6 +226,9 @@ static int parse_curlopt_key(const char *name, CURLoption *key, enum optiontype if (!strcasecmp(name, "header")) { *key = CURLOPT_HEADER; *ot = OT_BOOLEAN; + } else if (!strcasecmp(name, "httpheader")) { + *key = CURLOPT_HTTPHEADER; + *ot = OT_STRING; } else if (!strcasecmp(name, "proxy")) { *key = CURLOPT_PROXY; *ot = OT_STRING; @@ -390,16 +398,18 @@ yuck: return -1; } - /* Remove any existing entry */ + /* Remove any existing entry, only http headers are left */ AST_LIST_LOCK(list); - AST_LIST_TRAVERSE_SAFE_BEGIN(list, cur, list) { - if (cur->key == new->key) { - AST_LIST_REMOVE_CURRENT(list); - free(cur); - break; + if (new->key != CURLOPT_HTTPHEADER) { + AST_LIST_TRAVERSE_SAFE_BEGIN(list, cur, list) { + if (cur->key == new->key) { + AST_LIST_REMOVE_CURRENT(list); + free(cur); + break; + } } + AST_LIST_TRAVERSE_SAFE_END } - AST_LIST_TRAVERSE_SAFE_END /* Insert new entry */ ast_debug(1, "Inserting entry %p with key %d and value %p\n", new, new->key, new->value); @@ -605,6 +615,7 @@ static int acf_curl_helper(struct ast_channel *chan, const char *cmd, char *info ); CURL **curl; struct curl_settings *cur; + struct curl_slist *headers = NULL; struct ast_datastore *store = NULL; int hashcompat = 0; AST_LIST_HEAD(global_curl_info, curl_settings) *list = NULL; @@ -650,6 +661,8 @@ static int acf_curl_helper(struct ast_channel *chan, const char *cmd, char *info AST_LIST_TRAVERSE(&global_curl_info, cur, list) { if (cur->key == CURLOPT_SPECIAL_HASHCOMPAT) { hashcompat = (long) cur->value; + } else if (cur->key == CURLOPT_HTTPHEADER) { + headers = curl_slist_append(headers, (char*) cur->value); } else { curl_easy_setopt(*curl, cur->key, cur->value); } @@ -666,6 +679,8 @@ static int acf_curl_helper(struct ast_channel *chan, const char *cmd, char *info AST_LIST_TRAVERSE(list, cur, list) { if (cur->key == CURLOPT_SPECIAL_HASHCOMPAT) { hashcompat = (long) cur->value; + } else if (cur->key == CURLOPT_HTTPHEADER) { + headers = curl_slist_append(headers, (char*) cur->value); } else { curl_easy_setopt(*curl, cur->key, cur->value); } @@ -681,6 +696,10 @@ static int acf_curl_helper(struct ast_channel *chan, const char *cmd, char *info curl_easy_setopt(*curl, CURLOPT_POSTFIELDS, args.postdata); } + if (headers) { + curl_easy_setopt(*curl, CURLOPT_HTTPHEADER, headers); + } + /* Temporarily assign a buffer for curl to write errors to. */ curl_errbuf[0] = curl_errbuf[CURL_ERROR_SIZE] = '\0'; curl_easy_setopt(*curl, CURLOPT_ERRORBUFFER, curl_errbuf); @@ -698,6 +717,7 @@ static int acf_curl_helper(struct ast_channel *chan, const char *cmd, char *info if (store) { AST_LIST_UNLOCK(list); } + curl_slist_free_all(headers); if (args.postdata) { curl_easy_setopt(*curl, CURLOPT_POST, 0); @@ -781,6 +801,7 @@ static struct ast_custom_function acf_curlopt = { " ftptext - For FTP, force a text transfer (boolean)\n" " ftptimeout - For FTP, the server response timeout\n" " header - Retrieve header information (boolean)\n" +" httpheader - Add new custom http header (string)\n" " httptimeout - Number of seconds to wait for HTTP response\n" " maxredirs - Maximum number of redirects to follow\n" " proxy - Hostname or IP to use as a proxy\n"