http_client Implement failover between connections
authorOlle E. Johansson <oej@edvina.net>
Fri, 13 May 2016 21:01:30 +0000 (23:01 +0200)
committerOlle E. Johansson <oej@edvina.net>
Fri, 13 May 2016 21:01:30 +0000 (23:01 +0200)
If one http_connect attempt fails you can now switch to another server with
other settings automatically

modules/http_client/README
modules/http_client/doc/http_client_admin.xml
modules/http_client/functions.c

index e43fbd0..8c6b4a4 100644 (file)
@@ -510,6 +510,10 @@ modparam("http_client", "keep_connections", 1)
        maxdatasize modparam setting.
      * httpredirect Set to 1 for following HTTP 302 redirect. 0 to
        disable. Overrides the default httpredirect modparam.
+     * failover The name of another httpcon connection to use with the
+       same arguments in case a connection with this http_con fails.
+       Failure is either a connection failure or a response code of 500 or
+       above.
 
    Example 1.16. Set httpcon parameter
 ...
@@ -518,7 +522,7 @@ modparam("http_client", "httpcon", "apitwo=>http://atlanta.example.com/api/12")
 modparam("http_client", "httpcon", "apithree=>http://annabella:mysecret@atlanta.
 example.com/api/12")
 modparam("http_client", "httpcon", "apifour=>http://stockholm.example.com/api/ge
-tstuff;timeout=12")
+tstuff;timeout=12;failover=apione")
 ...
 
 3.17. config_file (string)
@@ -561,6 +565,7 @@ tstuff;timeout=12")
      * http_follow_redirect
      * httpproxy
      * httpproxyport
+     * failover
 
    See the "httpcon" module parameter for explanation of these settings.
 
index 76cb035..35dbe36 100644 (file)
@@ -505,6 +505,11 @@ modparam("http_client", "keep_connections", 1)
                                <emphasis>httpredirect</emphasis> Set to 1 for following HTTP 302
                                redirect. 0 to disable. Overrides the default httpredirect modparam.
                                </para></listitem>
+                               <listitem><para>
+                               <emphasis>failover</emphasis> The name of another <emphasis>httpcon</emphasis>
+                               connection to use with the same arguments in case a connection with this http_con fails.
+                               Failure is either a connection failure or a response code of 500 or above.
+                               </para></listitem>
                        </itemizedlist>
                        </para>
                        <example>
@@ -514,7 +519,7 @@ modparam("http_client", "keep_connections", 1)
 modparam("http_client", "httpcon", "apione=>http://atlanta.example.com")
 modparam("http_client", "httpcon", "apitwo=>http://atlanta.example.com/api/12")
 modparam("http_client", "httpcon", "apithree=>http://annabella:mysecret@atlanta.example.com/api/12")
-modparam("http_client", "httpcon", "apifour=>http://stockholm.example.com/api/getstuff;timeout=12")
+modparam("http_client", "httpcon", "apifour=>http://stockholm.example.com/api/getstuff;timeout=12;failover=apione")
 ...
                                </programlisting>
                        </example>
@@ -566,6 +571,7 @@ modparam("http_client", "httpcon", "apifour=>http://stockholm.example.com/api/ge
                                <listitem><para>http_follow_redirect</para></listitem>
                                <listitem><para>httpproxy</para></listitem>
                                <listitem><para>httpproxyport</para></listitem>
+                               <listitem><para>failover</para></listitem>
                        </itemizedlist>
                        See the "httpcon" module parameter for explanation of these settings.
                        <para>
index b70e86e..b5184be 100644 (file)
@@ -53,6 +53,7 @@ typedef struct {
        char *cacert;
        char *ciphersuites;
        char *http_proxy;
+       char *failovercon;
        unsigned int authmethod;
        unsigned int http_proxy_port;
        unsigned int tlsversion;
@@ -66,8 +67,6 @@ typedef struct {
        curl_con_pkg_t *pconn;
 } curl_query_t;
 
-/* Forward declaration */
-static int curL_query_url(struct sip_msg* _m, const char* _url, str* _dst, const curl_query_t * const query_params);
 
 /* 
  * curl write function that saves received data as zero terminated
@@ -103,6 +102,7 @@ size_t write_function( void *ptr, size_t size, size_t nmemb, void *stream_ptr)
  }
 
 
+
 /*! Send query to server, optionally post data.
  */
 static int curL_query_url(struct sip_msg* _m, const char* _url, str* _dst, const curl_query_t * const params)
@@ -246,6 +246,8 @@ static int curL_query_url(struct sip_msg* _m, const char* _url, str* _dst, const
                }
 
        }
+
+       /* Cleanup */
        if (headerlist) {
                curl_slist_free_all(headerlist);
        }
@@ -299,6 +301,10 @@ static int curL_query_url(struct sip_msg* _m, const char* _url, str* _dst, const
                        pkg_free(stream.buf);
                }
                counter_inc(connfail);
+               if (params->failovercon != NULL) {
+                       LM_ERR("FATAL FAILURE: Trying failover to curl con (%s)\n", params->failovercon);
+                       return (1000 + res);
+               }
                return res;
        }
 
@@ -370,6 +376,12 @@ static int curL_query_url(struct sip_msg* _m, const char* _url, str* _dst, const
                counter_inc(connok);
        } else {
                counter_inc(connfail);
+               if (stat >= 500) {
+                       if (params->failovercon != NULL) {
+                               LM_ERR("FAILURE: Trying failover to curl con (%s)\n", params->failovercon);
+                               return (1000 + stat);
+                       }
+               }
        }
 
        /* CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ... ); */
@@ -419,8 +431,9 @@ int curl_get_redirect(struct sip_msg* _m, const str *connection, str* result)
        return 1;
 }
 
+
 /*! Run a query based on a connection definition */
-int curl_con_query_url(struct sip_msg* _m, const str *connection, const str* url, str* result, const char *contenttype, const str* post)
+int curl_con_query_url_f(struct sip_msg* _m, const str *connection, const str* url, str* result, const char *contenttype, const str* post, int failover)
 {
        curl_con_t *conn = NULL;
        curl_con_pkg_t *pconn = NULL;
@@ -508,6 +521,7 @@ int curl_con_query_url(struct sip_msg* _m, const str *connection, const str* url
        query_params.oneline = 0;
        query_params.maxdatasize = maxdatasize;
        query_params.http_proxy_port = conn->http_proxy_port;
+       query_params.failovercon = conn->failover.s ? as_asciiz(&conn->failover) : NULL;
        query_params.pconn = pconn;
        if (conn->http_proxy) {
                query_params.http_proxy = conn->http_proxy;
@@ -518,6 +532,16 @@ int curl_con_query_url(struct sip_msg* _m, const str *connection, const str* url
 
        res = curL_query_url(_m, urlbuf, result, &query_params);
 
+       if (res > 1000 && conn->failover.s) {
+               int counter = failover + 1;
+               if (counter >= 2) {
+                       LM_DBG("**** No more failovers - returning failure\n");
+                       return (res - 1000);
+               }
+               /* Time for failover */
+               return curl_con_query_url_f(_m, &conn->failover, url, result, contenttype, post, counter);
+       }
+
        LM_DBG("***** #### ***** CURL DONE : %s \n", urlbuf);
 error:
        if (urlbuf != NULL) {
@@ -529,6 +553,11 @@ error:
        return res;
 }
 
+/* Wrapper */
+int curl_con_query_url(struct sip_msg* _m, const str *connection, const str* url, str* result, const char *contenttype, const str* post)
+{
+       return curl_con_query_url_f(_m, connection, url, result, contenttype, post, 0);
+}
 
 /*!
  * Performs http_query and saves possible result (first body line of reply)