]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
func_curl.c: Allow user to set what return codes constitute a failure.
authorDovid Bender <dovid@telecurve.com>
Sun, 18 Oct 2020 18:40:10 +0000 (18:40 +0000)
committerKevin Harwell <kharwell@digium.com>
Fri, 6 Nov 2020 18:39:27 +0000 (12:39 -0600)
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

configs/samples/res_curl.conf.sample
funcs/func_curl.c

index cc472989f236c2fac372a17d552e0d5047875c86..2487bb28ddb05cc7b7a6ea3a496f60e53a642698 100644 (file)
@@ -6,3 +6,4 @@
 proxytype=http
 proxyport=8001
 ;proxyuserpwd=asterisk:asteriskrocks
+;failurecodes=404,408,503
index cc3b195f2884a3ac7594bb77bd2640fd72c5cae7..3b04f120886131a8eceb9f06898c0d91732740e2 100644 (file)
                                                        </enum>
                                                </enumlist>
                                        </enum>
+                                       <enum name="failurecodes">
+                                               <para>A comma separated list of HTTP response codes to be treated as errors</para>
+                                       </enum>
                                </enumlist>
                        </parameter>
                </syntax>
 
 #define CURLOPT_SPECIAL_HASHCOMPAT ((CURLoption) -500)
 
+#define CURLOPT_SPECIAL_FAILURE_CODE 999
+
 static void curlds_free(void *data);
 
 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")) {
                *key = CURLOPT_SPECIAL_HASHCOMPAT;
                *ot = OT_ENUM;
+       } else if (!strcasecmp(name, "failurecodes")) {
+               *key = CURLOPT_SPECIAL_FAILURE_CODE;
+               *ot = OT_STRING;
        } else {
                return -1;
        }
@@ -655,7 +663,11 @@ struct curl_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);
-       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;
        struct curl_settings *cur;
        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_VECTOR_INIT(&hasfailurecode, 0); /*Initialize vector*/
        AST_LIST_LOCK(&global_curl_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 if (cur->key == CURLOPT_SPECIAL_FAILURE_CODE) {
+                       failurecodestrings = (char*) cur->value;
+                       while( (found = strsep(&failurecodestrings, ",")) != NULL) {
+                               AST_VECTOR_APPEND(&hasfailurecode, atoi(found));
+                       }
                } else {
                        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;
                                } else if (cur->key == CURLOPT_HTTPHEADER) {
                                        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 {
                                        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
         * CURLOPT_ERRORBUFFER" (62bcf005f4678a93158358265ba905bace33b834). */
        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) {
                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(values);
                }
-               ret = 0;
        }
 
        if (chan) {
@@ -885,6 +921,7 @@ static struct ast_custom_function acf_curlopt = {
 "  ssl_verifypeer - Whether to verify the peer certificate (boolean)\n"
 "  hashcompat     - Result data will be compatible for use with HASH()\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,
        .read2 = acf_curlopt_read2,