http_client: use strcpy() instead of strncpy() with sizeof dest buffer
[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                                 strcpy(params->pconn->result_content_type, ct);
348                         }
349                 }
350                 if(url) {
351                         LM_DBG("We visited URL: %s\n", url);
352                         if (params->pconn
353                                         && strlen(url)<sizeof(params->pconn->redirecturl)-1) {
354                                 strcpy(params->pconn->redirecturl, url);
355                         }
356                 }
357         }
358         if (params->pconn) {
359                 params->pconn->last_result = stat;
360         }
361
362         if ((stat >= 200) && (stat < 500)) {
363                 double datasize = 0;
364
365                 curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, &download_size);
366                 LM_DBG("  -- curl download size: %u \n", (unsigned int)download_size);
367                 datasize = download_size;
368
369                 if (download_size > 0) {
370
371                         if (params->oneline) {
372                                 /* search for line feed */
373                                 at = memchr(stream.buf, (char)10, download_size);
374                                 datasize = (double) (at - stream.buf);
375                                 LM_DBG("  -- curl download size cut to first line: %d \n",
376                                                 (int) datasize);
377                         }
378                         if (at == NULL) {
379                                 if (params->maxdatasize
380                                                 && ((unsigned int) download_size) > params->maxdatasize) {
381                                         /* Limit at maximum data size */
382                                         datasize = (double) params->maxdatasize;
383                                         LM_DBG("  -- curl download size cut to maxdatasize : %d \n",
384                                                         (int) datasize);
385                                 } else {
386                                         /* Limit at actual downloaded data size */
387                                         datasize = (double) download_size;
388                                         LM_DBG("  -- curl download size cut to download_size : %d \n",
389                                                         (int) datasize);
390                                         // at = stream.buf + (unsigned int) download_size;
391                                 }
392                         }
393                         /* Create a STR object */
394                         rval.s = stream.buf;
395                         rval.len = datasize;
396                         /* Duplicate string to return */
397                         pkg_str_dup(_dst, &rval);
398                         LM_DBG("curl query result - length: %d data: [%.*s]\n", rval.len,
399                                         rval.len, rval.s);
400                 } else {
401                         _dst->s = NULL;
402                         _dst->len = 0;
403                 }
404         }
405         if (stat == 200) {
406                 counter_inc(connok);
407         } else {
408                 counter_inc(connfail);
409                 if (stat >= 500) {
410                         if (params->failovercon != NULL) {
411                                 LM_ERR("FAILURE: Trying failover to curl con (%s)\n",
412                                                 params->failovercon);
413                                 return (1000 + stat);
414                         }
415                 }
416         }
417
418         /* CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ... ); */
419         if (params->pconn && params->keep_connections) {
420                 params->pconn->curl = curl;     /* Save connection, don't close */
421         } else {
422                 curl_easy_cleanup(curl);
423         }
424         if (stream.buf != NULL) {
425                 pkg_free(stream.buf);
426         }
427         return stat;
428 }
429
430 /*! Run a query based on a connection definition */
431 int curl_get_redirect(struct sip_msg* _m, const str *connection, str* result)
432 {
433         curl_con_t *conn = NULL;
434         curl_con_pkg_t *pconn = NULL;
435         str rval;
436         result->s = NULL;
437         result->len = 0;
438
439         /* Find connection if it exists */
440         if (!connection) {
441                 LM_ERR("No cURL connection specified\n");
442                 return -1;
443         }
444         LM_DBG("******** CURL Connection %.*s\n", connection->len, connection->s);
445         conn = curl_get_connection((str*)connection);
446         if (conn == NULL) {
447                 LM_ERR("No cURL connection found: %.*s\n", connection->len, connection->s);
448                 return -1;
449         }
450         pconn = curl_get_pkg_connection(conn);
451         if (pconn == NULL) {
452                 LM_ERR("No cURL connection data found: %.*s\n", connection->len, connection->s);
453                 return -1;
454         }
455                 /* Create a STR object */
456         rval.s = pconn->redirecturl;
457         rval.len = strlen(pconn->redirecturl);
458         /* Duplicate string to return */
459         pkg_str_dup(result, &rval);
460         LM_DBG("curl last redirect URL: Length %d %.*s \n", rval.len, rval.len, rval.s);
461
462         return 1;
463 }
464
465
466 /*! Run a query based on a connection definition */
467 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)
468 {
469         curl_con_t *conn = NULL;
470         curl_con_pkg_t *pconn = NULL;
471         char *urlbuf = NULL;
472         char *postdata = NULL;
473         curl_query_t query_params;
474
475         unsigned int maxdatasize = default_maxdatasize;
476         int res;
477
478         /* Find connection if it exists */
479         if (!connection) {
480                 LM_ERR("No cURL connection specified\n");
481                 return -1;
482         }
483         LM_DBG("******** CURL Connection %.*s\n", connection->len, connection->s);
484         conn = curl_get_connection((str*)connection);
485         if (conn == NULL) {
486                 LM_ERR("No cURL connection found: %.*s\n", connection->len, connection->s);
487                 return -1;
488         }
489         pconn = curl_get_pkg_connection(conn);
490         if (pconn == NULL) {
491                 LM_ERR("No cURL connection data found: %.*s\n", connection->len, connection->s);
492                 return -1;
493         }
494
495         LM_DBG("******** CURL Connection found %.*s\n", connection->len, connection->s);
496         maxdatasize = conn->maxdatasize;
497
498
499         if (url && (url->len > 0) && (url->s != NULL)) {
500                 int url_len = conn->schema.len + 3 + conn->url.len + 1 + url->len + 1;
501                 urlbuf = pkg_malloc(url_len);
502                 if (urlbuf == NULL) {
503                         res = -1;
504                         goto error;
505                 }
506                 snprintf(urlbuf, url_len, "%.*s://%.*s%s%.*s",
507                         conn->schema.len, conn->schema.s,
508                         conn->url.len, conn->url.s,
509                         (url->s[0] == '/')? "" : "/",
510                         url->len, url->s);
511         } else {
512                 int url_len = conn->schema.len + 3 + conn->url.len + 1;
513                 urlbuf = pkg_malloc(url_len);
514                 if (urlbuf == NULL) {
515                         res = -1;
516                         goto error;
517                 }
518                 snprintf(urlbuf, url_len, "%.*s://%.*s",
519                         conn->schema.len, conn->schema.s,
520                         conn->url.len, conn->url.s);
521         }
522         LM_DBG("***** #### ***** CURL URL: %s \n", urlbuf);
523
524         if (post && (post->len > 0) && (post->s != NULL)) {
525
526                 /* Allocated using pkg_memory */
527                 postdata = as_asciiz((str*)post);
528                 if (postdata  == NULL) {
529                         ERR("Curl: No memory left\n");
530                         res = -1;
531                         goto error;
532                 }
533                 LM_DBG("***** #### ***** CURL POST data: %s Content-type %s\n", postdata, contenttype);
534         }
535
536         memset(&query_params, 0, sizeof(curl_query_t));
537         query_params.username = conn->username;
538         query_params.secret = conn->password;
539         query_params.authmethod = conn->authmethod;
540         query_params.contenttype = contenttype ? (char*)contenttype : "text/plain";
541         query_params.post = postdata;
542         query_params.clientcert = conn->clientcert;
543         query_params.clientkey = conn->clientkey;
544         query_params.cacert = default_tls_cacert;
545         query_params.ciphersuites = conn->ciphersuites;
546         query_params.tlsversion = conn->tlsversion;
547         query_params.verify_peer = conn->verify_peer;
548         query_params.verify_host = conn->verify_host;
549         query_params.timeout = conn->timeout;
550         query_params.http_follow_redirect = conn->http_follow_redirect;
551         query_params.keep_connections = conn->keep_connections;
552         query_params.oneline = 0;
553         query_params.maxdatasize = maxdatasize;
554         query_params.http_proxy_port = conn->http_proxy_port;
555         query_params.failovercon = conn->failover.s ? as_asciiz(&conn->failover) : NULL;
556         query_params.pconn = pconn;
557         if (conn->http_proxy) {
558                 query_params.http_proxy = conn->http_proxy;
559                 LM_DBG("****** ##### CURL proxy [%s] \n", query_params.http_proxy);
560         } else {
561                 LM_DBG("**** Curl HTTP_proxy not set \n");
562         }
563
564         res = curL_query_url(_m, urlbuf, result, &query_params);
565
566         if (res > 1000 && conn->failover.s) {
567                 int counter = failover + 1;
568                 if (counter >= 2) {
569                         LM_DBG("**** No more failovers - returning failure\n");
570                         return (res - 1000);
571                 }
572                 /* Time for failover */
573                 return curl_con_query_url_f(_m, &conn->failover, url, result, contenttype, post, counter);
574         }
575
576         LM_DBG("***** #### ***** CURL DONE : %s \n", urlbuf);
577 error:
578         if (urlbuf != NULL) {
579                 pkg_free(urlbuf);
580         }
581         if (postdata != NULL) {
582                 pkg_free(postdata);
583         }
584         return res;
585 }
586
587 /* Wrapper */
588 int curl_con_query_url(struct sip_msg* _m, const str *connection,
589                 const str* url, str* result, const char *contenttype, const str* post)
590 {
591         return curl_con_query_url_f(_m, connection, url, result, contenttype, post, 0);
592 }
593
594 /*!
595  * Performs http_query and saves possible result (first body line of reply)
596  * to pvar.
597  * This is the same http_query as used to be in the utils module.
598  */
599 int http_client_query(struct sip_msg* _m, char* _url, str* _dst, char* _post,
600                 char* _hdrs)
601 {
602         int res;
603         curl_query_t query_params;
604
605         memset(&query_params, 0, sizeof(curl_query_t));
606         query_params.username = NULL;
607         query_params.secret = NULL;
608         query_params.authmethod = default_authmethod;
609         query_params.contenttype = NULL;
610         query_params.hdrs = _hdrs;
611         query_params.post = _post;
612         query_params.clientcert = NULL;
613         query_params.clientkey = NULL;
614         query_params.cacert = NULL;
615         query_params.ciphersuites = NULL;
616         query_params.tlsversion = default_tls_version;
617         query_params.verify_peer = default_tls_verify_peer;
618         query_params.verify_host = default_tls_verify_host;
619         query_params.timeout = default_connection_timeout;
620         query_params.http_follow_redirect = default_http_follow_redirect;
621         query_params.oneline = 1;
622         query_params.maxdatasize = 0;
623         if(default_useragent.s!=NULL && default_useragent.len>0) {
624                 query_params.useragent = default_useragent.s;
625         }
626         if(default_http_proxy.s!=NULL && default_http_proxy.len>0) {
627                 query_params.http_proxy = default_http_proxy.s;
628                 if(default_http_proxy_port>0) {
629                         query_params.http_proxy_port = default_http_proxy_port;
630                 }
631         }
632
633         res =  curL_query_url(_m, _url, _dst, &query_params);
634
635         return res;
636 }
637
638
639 char *http_get_content_type(const str *connection)
640 {
641         curl_con_t *conn = NULL;
642         curl_con_pkg_t *pconn = NULL;
643
644         /* Find connection if it exists */
645         if (!connection) {
646                 LM_ERR("No cURL connection specified\n");
647                 return NULL;
648         }
649         LM_DBG("******** CURL Connection %.*s\n", connection->len, connection->s);
650         conn = curl_get_connection((str*)connection);
651         if (conn == NULL) {
652                 LM_ERR("No cURL connection found: %.*s\n", connection->len, connection->s);
653                 return NULL;
654         }
655         pconn = curl_get_pkg_connection(conn);
656         if (pconn == NULL) {
657                 LM_ERR("No cURL connection data found: %.*s\n", connection->len, connection->s);
658                 return NULL;
659         }
660
661         return pconn->result_content_type;
662 }