func_curl.c: Allow user to set what return codes constitute a failure.

Currently any response from res_curl where we get an answer from the
web server, regardless of what the response is (404, 403 etc.) Asterisk
currently treats it as a success. This patch allows you to set which
codes should be considered as a failure by Asterisk. If say we set
failurecodes=404,403 then when using curl in realtime if a server gives
a 404 error Asterisk will try to failover to the next option set in
extconfig.conf

ASTERISK-28825

Reported by: Dovid Bender
Code by: Gobinda Paul

Change-Id: I94443e508343e0a3e535e51ea6e0562767639987
This commit is contained in:
Dovid Bender 2020-10-18 18:40:10 +00:00 committed by Kevin Harwell
parent 6baa4b53be
commit c635c78265
2 changed files with 40 additions and 2 deletions

View File

@ -6,3 +6,4 @@
proxytype=http proxytype=http
proxyport=8001 proxyport=8001
;proxyuserpwd=asterisk:asteriskrocks ;proxyuserpwd=asterisk:asteriskrocks
;failurecodes=404,408,503

View File

@ -187,6 +187,9 @@
</enum> </enum>
</enumlist> </enumlist>
</enum> </enum>
<enum name="failurecodes">
<para>A comma separated list of HTTP response codes to be treated as errors</para>
</enum>
</enumlist> </enumlist>
</parameter> </parameter>
</syntax> </syntax>
@ -206,6 +209,8 @@
#define CURLOPT_SPECIAL_HASHCOMPAT ((CURLoption) -500) #define CURLOPT_SPECIAL_HASHCOMPAT ((CURLoption) -500)
#define CURLOPT_SPECIAL_FAILURE_CODE 999
static void curlds_free(void *data); static void curlds_free(void *data);
static const struct ast_datastore_info curl_info = { static const struct ast_datastore_info curl_info = {
@ -318,6 +323,9 @@ static int parse_curlopt_key(const char *name, CURLoption *key, enum optiontype
} else if (!strcasecmp(name, "hashcompat")) { } else if (!strcasecmp(name, "hashcompat")) {
*key = CURLOPT_SPECIAL_HASHCOMPAT; *key = CURLOPT_SPECIAL_HASHCOMPAT;
*ot = OT_ENUM; *ot = OT_ENUM;
} else if (!strcasecmp(name, "failurecodes")) {
*key = CURLOPT_SPECIAL_FAILURE_CODE;
*ot = OT_STRING;
} else { } else {
return -1; return -1;
} }
@ -655,7 +663,11 @@ struct curl_args {
static int acf_curl_helper(struct ast_channel *chan, struct curl_args *args) static int acf_curl_helper(struct ast_channel *chan, struct curl_args *args)
{ {
struct ast_str *escapebuf = ast_str_thread_get(&thread_escapebuf, 16); struct ast_str *escapebuf = ast_str_thread_get(&thread_escapebuf, 16);
int ret = -1; int ret = 0;
long http_code = 0; /* read curl response */
size_t i;
struct ast_vector_int hasfailurecode = { NULL };
char *failurecodestrings,*found;
CURL **curl; CURL **curl;
struct curl_settings *cur; struct curl_settings *cur;
struct curl_slist *headers = NULL; struct curl_slist *headers = NULL;
@ -682,12 +694,18 @@ static int acf_curl_helper(struct ast_channel *chan, struct curl_args *args)
ast_autoservice_start(chan); ast_autoservice_start(chan);
} }
AST_VECTOR_INIT(&hasfailurecode, 0); /*Initialize vector*/
AST_LIST_LOCK(&global_curl_info); AST_LIST_LOCK(&global_curl_info);
AST_LIST_TRAVERSE(&global_curl_info, cur, list) { AST_LIST_TRAVERSE(&global_curl_info, cur, list) {
if (cur->key == CURLOPT_SPECIAL_HASHCOMPAT) { if (cur->key == CURLOPT_SPECIAL_HASHCOMPAT) {
hashcompat = (long) cur->value; hashcompat = (long) cur->value;
} else if (cur->key == CURLOPT_HTTPHEADER) { } else if (cur->key == CURLOPT_HTTPHEADER) {
headers = curl_slist_append(headers, (char*) cur->value); headers = curl_slist_append(headers, (char*) cur->value);
} else if (cur->key == CURLOPT_SPECIAL_FAILURE_CODE) {
failurecodestrings = (char*) cur->value;
while( (found = strsep(&failurecodestrings, ",")) != NULL) {
AST_VECTOR_APPEND(&hasfailurecode, atoi(found));
}
} else { } else {
curl_easy_setopt(*curl, cur->key, cur->value); curl_easy_setopt(*curl, cur->key, cur->value);
} }
@ -706,6 +724,11 @@ static int acf_curl_helper(struct ast_channel *chan, struct curl_args *args)
hashcompat = (long) cur->value; hashcompat = (long) cur->value;
} else if (cur->key == CURLOPT_HTTPHEADER) { } else if (cur->key == CURLOPT_HTTPHEADER) {
headers = curl_slist_append(headers, (char*) cur->value); headers = curl_slist_append(headers, (char*) cur->value);
} else if (cur->key == CURLOPT_SPECIAL_FAILURE_CODE) {
failurecodestrings = (char*) cur->value;
while( (found = strsep(&failurecodestrings, ",")) != NULL) {
AST_VECTOR_APPEND(&hasfailurecode, atoi(found));
}
} else { } else {
curl_easy_setopt(*curl, cur->key, cur->value); curl_easy_setopt(*curl, cur->key, cur->value);
} }
@ -739,6 +762,20 @@ static int acf_curl_helper(struct ast_channel *chan, struct curl_args *args)
* here, but the source allows it. See: "typecheck: allow NULL to unset * here, but the source allows it. See: "typecheck: allow NULL to unset
* CURLOPT_ERRORBUFFER" (62bcf005f4678a93158358265ba905bace33b834). */ * CURLOPT_ERRORBUFFER" (62bcf005f4678a93158358265ba905bace33b834). */
curl_easy_setopt(*curl, CURLOPT_ERRORBUFFER, (char*)NULL); curl_easy_setopt(*curl, CURLOPT_ERRORBUFFER, (char*)NULL);
curl_easy_getinfo (*curl, CURLINFO_RESPONSE_CODE, &http_code);
for (i = 0; i < AST_VECTOR_SIZE(&hasfailurecode); ++i) {
if (http_code == AST_VECTOR_GET(&hasfailurecode,i)){
ast_log(LOG_NOTICE, "%s%sCURL '%s' returned response code (%ld).\n",
chan ? ast_channel_name(chan) : "",
chan ? ast_channel_name(chan) : ": ",
args->url,
http_code);
ret=-1;
break;
}
}
AST_VECTOR_FREE(&hasfailurecode); /* Release the vector*/
if (store) { if (store) {
AST_LIST_UNLOCK(list); AST_LIST_UNLOCK(list);
@ -775,7 +812,6 @@ static int acf_curl_helper(struct ast_channel *chan, struct curl_args *args)
ast_free(fields); ast_free(fields);
ast_free(values); ast_free(values);
} }
ret = 0;
} }
if (chan) { if (chan) {
@ -885,6 +921,7 @@ static struct ast_custom_function acf_curlopt = {
" ssl_verifypeer - Whether to verify the peer certificate (boolean)\n" " ssl_verifypeer - Whether to verify the peer certificate (boolean)\n"
" hashcompat - Result data will be compatible for use with HASH()\n" " hashcompat - Result data will be compatible for use with HASH()\n"
" - if value is \"legacy\", will translate '+' to ' '\n" " - if value is \"legacy\", will translate '+' to ' '\n"
" failurecodes - A comma separated list of HTTP response codes to be treated as errors\n"
"", "",
.read = acf_curlopt_read, .read = acf_curlopt_read,
.read2 = acf_curlopt_read2, .read2 = acf_curlopt_read2,