c4fc39d6a4753896be4cec339ee9b23294f04286
[sip-router] / src / modules / http_client / functions.c
1 /*
2  * Script functions of http_client module
3  *
4  * Copyright (C) 2015 Olle E. Johansson, Edvina AB
5  *
6  * Based on functions from siputil
7  *      Copyright (C) 2008 Juha Heinanen
8  *      Copyright (C) 2013 Carsten Bock, ng-voice GmbH
9  *
10  * This file is part of Kamailio, a free SIP server.
11  *
12  * Kamailio is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version
16  *
17  * Kamailio is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License 
23  * along with this program; if not, write to the Free Software 
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
25  *
26  */
27
28 /*!
29  * \file
30  * \brief Kamailio http_client :: script functions
31  * \ingroup http_client
32  * Module: \ref http_client
33  */
34
35
36 #include "../../core/mod_fix.h"
37 #include "../../core/pvar.h"
38 #include "../../core/route_struct.h"
39 #include "../../core/ut.h"
40 #include "../../core/mem/mem.h"
41 #include "../../core/parser/msg_parser.h"
42
43 #include "http_client.h"
44 #include "curlcon.h"
45
46 typedef struct {
47         char *username;
48         char *secret;
49         char *contenttype;
50         char *post;
51         char *clientcert;
52         char *clientkey;
53         char *cacert;
54         char *ciphersuites;
55         char *http_proxy;
56         char *failovercon;
57         char *useragent;
58         char *hdrs;
59         unsigned int authmethod;
60         unsigned int http_proxy_port;
61         unsigned int tlsversion;
62         unsigned int verify_peer;
63         unsigned int verify_host;
64         unsigned int timeout;
65         unsigned int http_follow_redirect;
66         unsigned int oneline;
67         unsigned int maxdatasize;
68         unsigned int keep_connections;
69         curl_con_pkg_t *pconn;
70 } curl_query_t;
71
72
73 /*
74  * curl write function that saves received data as zero terminated
75  * to stream. Returns the amount of data taken care of.
76  *
77  * This function may be called multiple times for larger responses,
78  * so it reallocs + concatenates the buffer as needed.
79  */
80 size_t write_function( void *ptr, size_t size, size_t nmemb, void *stream_ptr)
81 {
82         curl_res_stream_t *stream = (curl_res_stream_t *) stream_ptr;
83
84
85         if (stream->max_size == 0 || stream->curr_size < stream->max_size) {
86                 char *tmp = (char *) pkg_realloc(stream->buf, stream->curr_size + (size * nmemb));
87
88                 if (tmp == NULL) {
89                         LM_ERR("cannot allocate memory for stream\n");
90                         return CURLE_WRITE_ERROR;
91                 }
92                 stream->buf = tmp;
93
94                 memcpy(&stream->buf[stream->pos], (char *) ptr, (size * nmemb));
95
96                 stream->curr_size += ((size * nmemb));
97                 stream->pos += (size * nmemb);
98
99         }  else {
100                 LM_DBG("****** ##### CURL Max datasize exceeded: max  %u current %u\n", (unsigned int) stream->max_size, (unsigned int)stream->curr_size);
101         }
102
103         return size * nmemb;
104  }
105
106
107
108 /*! Send query to server, optionally post data.
109  */
110 static int curL_query_url(struct sip_msg* _m, const char* _url, str* _dst,
111                 const curl_query_t * const params)
112 {
113         CURL *curl = NULL;;
114         CURLcode res;
115         char *at = NULL;
116         curl_res_stream_t stream;
117         long stat = 0;
118         str rval = STR_NULL;
119         double download_size = 0;
120         struct curl_slist *headerlist = NULL;
121
122         memset(&stream, 0, sizeof(curl_res_stream_t));
123         stream.max_size = (size_t) params->maxdatasize;
124
125         if(params->pconn) {
126                 LM_DBG("****** ##### We have a pconn - keep_connections: %d!\n",
127                                 params->keep_connections);
128                 params->pconn->result_content_type[0] = '\0';
129                 params->pconn->redirecturl[0] = '\0';
130                 if (params->pconn->curl != NULL) {
131                         LM_DBG("         ****** ##### Reusing existing connection if possible\n");
132                         curl = params->pconn->curl;     /* Reuse existing handle */
133                         curl_easy_reset(curl);          /* Reset handle */
134                 }
135         }
136
137
138         if (curl == NULL) {
139                 curl = curl_easy_init();
140         }
141         if (curl == NULL) {
142                 LM_ERR("Failed to initialize curl connection\n");
143                 return -1;
144         }
145
146         LM_DBG("****** ##### CURL URL [%s] \n", _url);
147         res = curl_easy_setopt(curl, CURLOPT_URL, _url);
148
149         /* Limit to HTTP and HTTPS protocols */
150         res = curl_easy_setopt(curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
151         res = curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
152
153         if (params->post) {
154                 /* Now specify we want to POST data */
155                 res |= curl_easy_setopt(curl, CURLOPT_POST, 1L);
156
157                 if(params->contenttype) {
158                         char ctype[256];
159
160                         ctype[0] = '\0';
161                         snprintf(ctype, sizeof(ctype), "Content-Type: %s", params->contenttype);
162
163                         /* Set the content-type of the DATA */
164                         headerlist = curl_slist_append(headerlist, ctype);
165                 }
166
167                 /* Tell CURL we want to upload using POST */
168                 res |= curl_easy_setopt(curl, CURLOPT_POSTFIELDS, params->post);
169
170         } else {
171                 /* Reset post option */
172                 res |= curl_easy_setopt(curl, CURLOPT_POST, 0L);
173         }
174
175         if (params->hdrs) {
176                 headerlist = curl_slist_append(headerlist, params->hdrs);
177         }
178         if(headerlist) {
179                 res |= curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
180         }
181
182         if (params->maxdatasize) {
183                 /* Maximum data size to download - we always download full response,
184                  * but cut it off before moving to pvar */
185                 LM_DBG("****** ##### CURL Max datasize %u\n", params->maxdatasize);
186         }
187
188         if (params->username) {
189                 res |= curl_easy_setopt(curl, CURLOPT_USERNAME, params->username);
190                 res |= curl_easy_setopt(curl, CURLOPT_HTTPAUTH, params->authmethod);
191         }
192         if (params->secret) {
193                 res |= curl_easy_setopt(curl, CURLOPT_PASSWORD, params->secret);
194         }
195
196         /* Client certificate */
197         if (params->clientcert != NULL && params->clientkey != NULL) {
198                 res |= curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM");
199                 res |= curl_easy_setopt(curl, CURLOPT_SSLCERT, params->clientcert);
200
201                 res |= curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, "PEM");
202                 res |= curl_easy_setopt(curl, CURLOPT_SSLKEY, params->clientkey);
203         }
204
205         if (params->cacert != NULL) {
206                 res |= curl_easy_setopt(curl, CURLOPT_CAINFO, params->cacert);
207         }
208
209         if (params->tlsversion != CURL_SSLVERSION_DEFAULT) {
210                 res |= curl_easy_setopt(curl, CURLOPT_SSLVERSION,
211                                 (long) params->tlsversion);
212         }
213
214         if (params->ciphersuites != NULL) {
215                 res |= curl_easy_setopt(curl, CURLOPT_SSL_CIPHER_LIST,
216                                 params->ciphersuites);
217         }
218
219         if (params->http_proxy  != NULL) {
220                 LM_DBG("****** ##### CURL proxy [%s] \n", params->http_proxy);
221                 res |= curl_easy_setopt(curl, CURLOPT_PROXY, params->http_proxy);
222         } else {
223                 LM_DBG("****** ##### CURL proxy NOT SET \n");
224         }
225
226         if (params->http_proxy_port > 0) {
227                 res |= curl_easy_setopt(curl, CURLOPT_PROXYPORT,
228                                 params->http_proxy_port);
229         }
230
231
232         res |= curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER,
233                         (long) params->verify_peer);
234         res |= curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST,
235                         (long) params->verify_host?2:0);
236
237         res |= curl_easy_setopt(curl, CURLOPT_NOSIGNAL, (long) 1);
238         res |= curl_easy_setopt(curl, CURLOPT_TIMEOUT, (long) params->timeout);
239         res |= curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION,
240                         (long) params->http_follow_redirect);
241         if (params->http_follow_redirect) {
242                 LM_DBG("Following redirects for this request! \n");
243         }
244
245
246         res |= curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_function);
247         res |= curl_easy_setopt(curl, CURLOPT_WRITEDATA, &stream);
248
249         if(params->useragent)
250                 res |= curl_easy_setopt(curl, CURLOPT_USERAGENT, params->useragent);
251
252         if (res != CURLE_OK) {
253                 /* PANIC */
254                 LM_ERR("Could not set CURL options. Library error \n");
255         } else {
256                 double totaltime, connecttime;
257
258                 res = curl_easy_perform(curl);
259
260                 curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &totaltime);
261                 curl_easy_getinfo(curl, CURLINFO_APPCONNECT_TIME, &connecttime);
262                 LM_DBG("HTTP Call performed in %f s (connect time %f) \n",
263                                 totaltime, connecttime);
264                 if (params->pconn) {
265                         params->pconn->querytime = totaltime;
266                         params->pconn->connecttime = connecttime;
267                 }
268
269         }
270
271         /* Cleanup */
272         if (headerlist) {
273                 curl_slist_free_all(headerlist);
274         }
275
276         if (res != CURLE_OK) {
277                 /* http://curl.haxx.se/libcurl/c/libcurl-errors.html */
278                 if (res == CURLE_COULDNT_CONNECT) {
279                         LM_WARN("failed to connect() to host\n");
280                 } else if ( res == CURLE_COULDNT_RESOLVE_HOST ) {
281                         LM_WARN("Couldn't resolve host\n");
282                 } else if ( res == CURLE_COULDNT_RESOLVE_PROXY ) {
283                         LM_WARN("Couldn't resolve http_proxy host\n");
284                 } else if ( res == CURLE_UNSUPPORTED_PROTOCOL ) {
285                         LM_WARN("URL Schema not supported by curl\n");
286                 } else if ( res == CURLE_URL_MALFORMAT ) {
287                         LM_WARN("Malformed URL used in http_client\n");
288                 } else if ( res == CURLE_OUT_OF_MEMORY ) {
289                         LM_WARN("Curl library out of memory\n");
290                 } else if ( res == CURLE_OPERATION_TIMEDOUT ) {
291                         LM_WARN("Curl library timed out on request\n");
292                 } else if ( res == CURLE_SSL_CONNECT_ERROR ) {
293                         LM_WARN("TLS error in curl connection\n");
294                 } else if ( res == CURLE_SSL_CERTPROBLEM ) {
295                         LM_WARN("TLS local certificate error\n");
296                 } else if ( res == CURLE_SSL_CIPHER ) {
297                         LM_WARN("TLS cipher error\n");
298                 } else if ( res == CURLE_SSL_CACERT ) {
299                         LM_WARN("TLS server certificate validation error (No valid CA cert)\n");
300                 } else if ( res == CURLE_SSL_CACERT_BADFILE ) {
301                         LM_WARN("TLS CA certificate read error \n");
302                 } else if ( res == CURLE_SSL_ISSUER_ERROR ) {
303                         LM_WARN("TLS issuer certificate check error \n");
304                 } else if ( res == CURLE_PEER_FAILED_VERIFICATION ) {
305                         LM_WARN("TLS verification error\n");
306                 } else if ( res == CURLE_TOO_MANY_REDIRECTS ) {
307                         LM_WARN("Too many redirects\n");
308                 } else {
309                         LM_ERR("failed to perform curl (%d)\n", res);
310                 }
311
312                 if (params->pconn) {
313                         params->pconn->last_result = res;
314                 }
315                 if (params->pconn && params->keep_connections) {
316                         params->pconn->curl = curl;     /* Save connection, don't close */
317                 } else {
318                         /* Cleanup and close - bye bye and thank you for all the bytes */
319                         curl_easy_cleanup(curl);
320                 }
321                 if(stream.buf) {
322                         pkg_free(stream.buf);
323                 }
324                 counter_inc(connfail);
325                 if (params->failovercon != NULL) {
326                         LM_ERR("FATAL FAILURE: Trying failover to curl con (%s)\n",
327                                         params->failovercon);
328                         return (1000 + res);
329                 }
330                 return res;
331         }
332
333         /* HTTP_CODE CHANGED TO CURLINFO_RESPONSE_CODE in curl > 7.10.7 */
334         curl_easy_getinfo(curl, CURLINFO_HTTP_CODE, &stat);
335         if(res == CURLE_OK) {
336                 char *ct = NULL;
337                 char *url = NULL;
338
339                 /* ask for the content-type of the response */
340                 res = curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &ct);
341                 res |= curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &url);
342
343                 if(ct) {
344                         LM_DBG("We received Content-Type: %s\n", ct);
345                         if (params->pconn &&
346                                         strlen(ct)<sizeof(params->pconn->result_content_type)-1) {
347                                 strncpy(params->pconn->result_content_type, ct,
348                                                 sizeof(params->pconn->result_content_type));
349                         }
350                 }
351                 if(url) {
352                         LM_DBG("We visited URL: %s\n", url);
353                         if (params->pconn
354                                         && strlen(url)<sizeof(params->pconn->redirecturl)-1) {
355                                 strncpy(params->pconn->redirecturl, url ,
356                                                 sizeof(params->pconn->redirecturl));
357                         }
358                 }
359         }
360         if (params->pconn) {
361                 params->pconn->last_result = stat;
362         }
363
364         if ((stat >= 200) && (stat < 500)) {
365                 double datasize = 0;
366
367                 curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, &download_size);
368                 LM_DBG("  -- curl download size: %u \n", (unsigned int)download_size);
369                 datasize = download_size;
370
371                 if (download_size > 0) {
372
373                         if (params->oneline) {
374                                 /* search for line feed */
375                                 at = memchr(stream.buf, (char)10, download_size);
376                                 datasize = (double) (at - stream.buf);
377                                 LM_DBG("  -- curl download size cut to first line: %d \n",
378                                                 (int) datasize);
379                         }
380                         if (at == NULL) {
381                                 if (params->maxdatasize
382                                                 && ((unsigned int) download_size) > params->maxdatasize) {
383                                         /* Limit at maximum data size */
384                                         datasize = (double) params->maxdatasize;
385                                         LM_DBG("  -- curl download size cut to maxdatasize : %d \n",
386                                                         (int) datasize);
387                                 } else {
388                                         /* Limit at actual downloaded data size */
389                                         datasize = (double) download_size;
390                                         LM_DBG("  -- curl download size cut to download_size : %d \n",
391                                                         (int) datasize);
392                                         // at = stream.buf + (unsigned int) download_size;
393                                 }
394                         }
395                         /* Create a STR object */
396                         rval.s = stream.buf;
397                         rval.len = datasize;
398                         /* Duplicate string to return */
399                         pkg_str_dup(_dst, &rval);
400                         LM_DBG("curl query result - length: %d data: [%.*s]\n", rval.len,
401                                         rval.len, rval.s);
402                 } else {
403                         _dst->s = NULL;
404                         _dst->len = 0;
405                 }
406         }
407         if (stat == 200) {
408                 counter_inc(connok);
409         } else {
410                 counter_inc(connfail);
411                 if (stat >= 500) {
412                         if (params->failovercon != NULL) {
413                                 LM_ERR("FAILURE: Trying failover to curl con (%s)\n",
414                                                 params->failovercon);
415                                 return (1000 + stat);
416                         }
417                 }
418         }
419
420         /* CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ... ); */
421         if (params->pconn && params->keep_connections) {
422                 params->pconn->curl = curl;     /* Save connection, don't close */
423         } else {
424                 curl_easy_cleanup(curl);
425         }
426         if (stream.buf != NULL) {
427                 pkg_free(stream.buf);
428         }
429         return stat;
430 }
431
432 /*! Run a query based on a connection definition */
433 int curl_get_redirect(struct sip_msg* _m, const str *connection, str* result)
434 {
435         curl_con_t *conn = NULL;
436         curl_con_pkg_t *pconn = NULL;
437         str rval;
438         result->s = NULL;
439         result->len = 0;
440
441         /* Find connection if it exists */
442         if (!connection) {
443                 LM_ERR("No cURL connection specified\n");
444                 return -1;
445         }
446         LM_DBG("******** CURL Connection %.*s\n", connection->len, connection->s);
447         conn = curl_get_connection((str*)connection);
448         if (conn == NULL) {
449                 LM_ERR("No cURL connection found: %.*s\n", connection->len, connection->s);
450                 return -1;
451         }
452         pconn = curl_get_pkg_connection(conn);
453         if (pconn == NULL) {
454                 LM_ERR("No cURL connection data found: %.*s\n", connection->len, connection->s);
455                 return -1;
456         }
457                 /* Create a STR object */
458         rval.s = pconn->redirecturl;
459         rval.len = strlen(pconn->redirecturl);
460         /* Duplicate string to return */
461         pkg_str_dup(result, &rval);
462         LM_DBG("curl last redirect URL: Length %d %.*s \n", rval.len, rval.len, rval.s);
463
464         return 1;
465 }
466
467
468 /*! Run a query based on a connection definition */
469 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)
470 {
471         curl_con_t *conn = NULL;
472         curl_con_pkg_t *pconn = NULL;
473         char *urlbuf = NULL;
474         char *postdata = NULL;
475         curl_query_t query_params;
476
477         unsigned int maxdatasize = default_maxdatasize;
478         int res;
479
480         /* Find connection if it exists */
481         if (!connection) {
482                 LM_ERR("No cURL connection specified\n");
483                 return -1;
484         }
485         LM_DBG("******** CURL Connection %.*s\n", connection->len, connection->s);
486         conn = curl_get_connection((str*)connection);
487         if (conn == NULL) {
488                 LM_ERR("No cURL connection found: %.*s\n", connection->len, connection->s);
489                 return -1;
490         }
491         pconn = curl_get_pkg_connection(conn);
492         if (pconn == NULL) {
493                 LM_ERR("No cURL connection data found: %.*s\n", connection->len, connection->s);
494                 return -1;
495         }
496
497         LM_DBG("******** CURL Connection found %.*s\n", connection->len, connection->s);
498         maxdatasize = conn->maxdatasize;
499
500
501         if (url && (url->len > 0) && (url->s != NULL)) {
502                 int url_len = conn->schema.len + 3 + conn->url.len + 1 + url->len + 1;
503                 urlbuf = pkg_malloc(url_len);
504                 if (urlbuf == NULL) {
505                         res = -1;
506                         goto error;
507                 }
508                 snprintf(urlbuf, url_len, "%.*s://%.*s%s%.*s",
509                         conn->schema.len, conn->schema.s,
510                         conn->url.len, conn->url.s,
511                         (url->s[0] == '/')? "" : "/",
512                         url->len, url->s);
513         } else {
514                 int url_len = conn->schema.len + 3 + conn->url.len + 1;
515                 urlbuf = pkg_malloc(url_len);
516                 if (urlbuf == NULL) {
517                         res = -1;
518                         goto error;
519                 }
520                 snprintf(urlbuf, url_len, "%.*s://%.*s",
521                         conn->schema.len, conn->schema.s,
522                         conn->url.len, conn->url.s);
523         }
524         LM_DBG("***** #### ***** CURL URL: %s \n", urlbuf);
525
526         if (post && (post->len > 0) && (post->s != NULL)) {
527
528                 /* Allocated using pkg_memory */
529                 postdata = as_asciiz((str*)post);
530                 if (postdata  == NULL) {
531                         ERR("Curl: No memory left\n");
532                         res = -1;
533                         goto error;
534                 }
535                 LM_DBG("***** #### ***** CURL POST data: %s Content-type %s\n", postdata, contenttype);
536         }
537
538         memset(&query_params, 0, sizeof(curl_query_t));
539         query_params.username = conn->username;
540         query_params.secret = conn->password;
541         query_params.authmethod = conn->authmethod;
542         query_params.contenttype = contenttype ? (char*)contenttype : "text/plain";
543         query_params.post = postdata;
544         query_params.clientcert = conn->clientcert;
545         query_params.clientkey = conn->clientkey;
546         query_params.cacert = default_tls_cacert;
547         query_params.ciphersuites = conn->ciphersuites;
548         query_params.tlsversion = conn->tlsversion;
549         query_params.verify_peer = conn->verify_peer;
550         query_params.verify_host = conn->verify_host;
551         query_params.timeout = conn->timeout;
552         query_params.http_follow_redirect = conn->http_follow_redirect;
553         query_params.keep_connections = conn->keep_connections;
554         query_params.oneline = 0;
555         query_params.maxdatasize = maxdatasize;
556         query_params.http_proxy_port = conn->http_proxy_port;
557         query_params.failovercon = conn->failover.s ? as_asciiz(&conn->failover) : NULL;
558         query_params.pconn = pconn;
559         if (conn->http_proxy) {
560                 query_params.http_proxy = conn->http_proxy;
561                 LM_DBG("****** ##### CURL proxy [%s] \n", query_params.http_proxy);
562         } else {
563                 LM_DBG("**** Curl HTTP_proxy not set \n");
564         }
565
566         res = curL_query_url(_m, urlbuf, result, &query_params);
567
568         if (res > 1000 && conn->failover.s) {
569                 int counter = failover + 1;
570                 if (counter >= 2) {
571                         LM_DBG("**** No more failovers - returning failure\n");
572                         return (res - 1000);
573                 }
574                 /* Time for failover */
575                 return curl_con_query_url_f(_m, &conn->failover, url, result, contenttype, post, counter);
576         }
577
578         LM_DBG("***** #### ***** CURL DONE : %s \n", urlbuf);
579 error:
580         if (urlbuf != NULL) {
581                 pkg_free(urlbuf);
582         }
583         if (postdata != NULL) {
584                 pkg_free(postdata);
585         }
586         return res;
587 }
588
589 /* Wrapper */
590 int curl_con_query_url(struct sip_msg* _m, const str *connection,
591                 const str* url, str* result, const char *contenttype, const str* post)
592 {
593         return curl_con_query_url_f(_m, connection, url, result, contenttype, post, 0);
594 }
595
596 /*!
597  * Performs http_query and saves possible result (first body line of reply)
598  * to pvar.
599  * This is the same http_query as used to be in the utils module.
600  */
601 int http_client_query(struct sip_msg* _m, char* _url, str* _dst, char* _post,
602                 char* _hdrs)
603 {
604         int res;
605         curl_query_t query_params;
606
607         memset(&query_params, 0, sizeof(curl_query_t));
608         query_params.username = NULL;
609         query_params.secret = NULL;
610         query_params.authmethod = default_authmethod;
611         query_params.contenttype = NULL;
612         query_params.hdrs = _hdrs;
613         query_params.post = _post;
614         query_params.clientcert = NULL;
615         query_params.clientkey = NULL;
616         query_params.cacert = NULL;
617         query_params.ciphersuites = NULL;
618         query_params.tlsversion = default_tls_version;
619         query_params.verify_peer = default_tls_verify_peer;
620         query_params.verify_host = default_tls_verify_host;
621         query_params.timeout = default_connection_timeout;
622         query_params.http_follow_redirect = default_http_follow_redirect;
623         query_params.oneline = 1;
624         query_params.maxdatasize = 0;
625         if(default_useragent.s!=NULL && default_useragent.len>0) {
626                 query_params.useragent = default_useragent.s;
627         }
628         if(default_http_proxy.s!=NULL && default_http_proxy.len>0) {
629                 query_params.http_proxy = default_http_proxy.s;
630                 if(default_http_proxy_port>0) {
631                         query_params.http_proxy_port = default_http_proxy_port;
632                 }
633         }
634
635         res =  curL_query_url(_m, _url, _dst, &query_params);
636
637         return res;
638 }
639
640
641 char *http_get_content_type(const str *connection)
642 {
643         curl_con_t *conn = NULL;
644         curl_con_pkg_t *pconn = NULL;
645
646         /* Find connection if it exists */
647         if (!connection) {
648                 LM_ERR("No cURL connection specified\n");
649                 return NULL;
650         }
651         LM_DBG("******** CURL Connection %.*s\n", connection->len, connection->s);
652         conn = curl_get_connection((str*)connection);
653         if (conn == NULL) {
654                 LM_ERR("No cURL connection found: %.*s\n", connection->len, connection->s);
655                 return NULL;
656         }
657         pconn = curl_get_pkg_connection(conn);
658         if (pconn == NULL) {
659                 LM_ERR("No cURL connection data found: %.*s\n", connection->len, connection->s);
660                 return NULL;
661         }
662
663         return pconn->result_content_type;
664 }