Преглед изворни кода

http_client Implement failover between connections

If one http_connect attempt fails you can now switch to another server with
other settings automatically
Olle E. Johansson пре 9 година
родитељ
комит
da0dbbcd2e

+ 6 - 1
modules/http_client/README

@@ -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.
 

+ 7 - 1
modules/http_client/doc/http_client_admin.xml

@@ -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:[email protected]/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>

+ 32 - 3
modules/http_client/functions.c

@@ -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)