http_client Fix bad formatting of source code
[sip-router] / modules / http_client / http_client.c
1 /*
2  * http_client Module
3  * Copyright (C) 2015-2016 Edvina AB, Olle E. Johansson
4  *
5  * Based on part of the utils module and part
6  * of the json-rpc-c module
7  *
8  * Copyright (C) 2008 Juha Heinanen
9  * Copyright (C) 2009 1&1 Internet AG
10  * Copyright (C) 2013 Carsten Bock, ng-voice GmbH
11  *
12  * This file is part of Kamailio, a free SIP server.
13  *
14  * Kamailio is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version
18  *
19  * Kamailio is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License 
25  * along with this program; if not, write to the Free Software 
26  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
27  *
28  */
29
30 /*! \file
31  * \brief  Kamailio http_client :: The module interface file
32  * \ingroup http_client
33  */
34
35 /*! \defgroup http_client Kamailio :: Module interface to Curl
36  *
37  * http://curl.haxx.se
38  * A generic library for many protocols
39  *
40  *  http_connect(connection, url, $avp)
41  *  http_connect(connection, url, content-type, data, $avp)
42  *
43  *      $var(res) = http_connect("anders", "/postl├ąda", "application/json", "{ ok, {200, ok}}", "$avp(gurka)");
44  *      $var(res) = http_connect("anders", "/postl├ąda", "application/json", "$var(tomat)", "$avp(gurka)");
45  *
46  */
47
48
49 #include <curl/curl.h>
50
51 #include "../../mod_fix.h"
52 #include "../../sr_module.h"
53 #include "../../ut.h"
54 #include "../../resolve.h"
55 #include "../../locking.h"
56 #include "../../script_cb.h"
57 #include "../../mem/shm_mem.h"
58 #include "../../lib/srdb1/db.h"
59 #include "../../rpc.h"
60 #include "../../rpc_lookup.h"
61 #include "../../config.h"
62 #include "../../lvalue.h"
63 #include "../../pt.h"           /* Process table */
64
65 #include "functions.h"
66 #include "curlcon.h"
67 #include "curlrpc.h"
68 #include "curl_api.h"
69
70 MODULE_VERSION
71
72 #define CURL_USER_AGENT  NAME  " (" VERSION " (" ARCH "/" OS_QUOTED "))"
73 #define CURL_USER_AGENT_LEN (sizeof(CURL_USER_AGENT)-1)
74
75 /* Module parameter variables */
76 unsigned int    default_connection_timeout = 4;
77 char            *default_tls_cacert = NULL;             /*!< File name: Default CA cert to use for curl TLS connection */
78 str             default_tls_clientcert = STR_NULL;      /*!< File name: Default client certificate to use for curl TLS connection */
79 str             default_tls_clientkey = STR_NULL;       /*!< File name: Key in PEM format that belongs to client cert */
80 str             default_cipher_suite_list = STR_NULL;   /*!< List of allowed cipher suites */
81 unsigned int    default_tls_version = 0;                /*!< 0 = Use libcurl default */
82 unsigned int    default_tls_verify_peer = 1;            /*!< 0 = Do not verify TLS server cert. 1 = Verify TLS cert (default) */
83 unsigned int    default_tls_verify_host = 2;            /*!< 0 = Do not verify TLS server CN/SAN  2 = Verify TLS server CN/SAN (default) */
84 str             default_http_proxy = STR_NULL;          /*!< Default HTTP proxy to use */
85 unsigned int    default_http_proxy_port = 0;            /*!< Default HTTP proxy port to use */
86 unsigned int    default_http_follow_redirect = 0;       /*!< Follow HTTP redirects CURLOPT_FOLLOWLOCATION */
87 unsigned int    default_keep_connections = 0;           /*!< Keep http connections open for reuse */
88 str             default_useragent = { CURL_USER_AGENT, CURL_USER_AGENT_LEN };   /*!< Default CURL useragent. Default "Kamailio Curl " */
89 unsigned int    default_maxdatasize = 0;                /*!< Default download size. 0=disabled */
90 unsigned int    default_authmethod = CURLAUTH_BASIC | CURLAUTH_DIGEST;          /*!< authentication method - Basic, Digest or both */
91
92 str             http_client_config_file = STR_NULL;
93
94 static curl_version_info_data *curl_info;
95
96 /* Module management function prototypes */
97 static int mod_init(void);
98 static int child_init(int);
99 static void destroy(void);
100
101 /* Fixup functions to be defined later */
102 static int fixup_http_query_get(void** param, int param_no);
103 static int fixup_free_http_query_get(void** param, int param_no);
104 static int fixup_http_query_post(void** param, int param_no);
105 static int fixup_free_http_query_post(void** param, int param_no);
106
107 static int fixup_curl_connect(void** param, int param_no);
108 static int fixup_free_curl_connect(void** param, int param_no);
109 static int fixup_curl_connect_post(void** param, int param_no);
110 static int fixup_free_curl_connect_post(void** param, int param_no);
111 static int w_curl_connect_post(struct sip_msg* _m, char* _con, char * _url, char* _result, char* _ctype, char* _data);
112
113 static int fixup_curl_get_redirect(void** param, int param_no);
114 static int fixup_free_curl_get_redirect(void** param, int param_no);
115 static int w_curl_get_redirect(struct sip_msg* _m, char* _con, char* _result);
116
117 /* Wrappers for http_query to be defined later */
118 static int w_http_query(struct sip_msg* _m, char* _url, char* _result);
119 static int w_http_query_post(struct sip_msg* _m, char* _url, char* _post, char* _result);
120 static int w_curl_connect(struct sip_msg* _m, char* _con, char * _url, char* _result);
121
122 /* forward function */
123 static int curl_con_param(modparam_t type, void* val);
124 static int pv_parse_curlerror(pv_spec_p sp, str *in);
125 static int pv_get_curlerror(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
126
127 /* Exported functions */
128 static cmd_export_t cmds[] = {
129         {"http_client_query", (cmd_function)w_http_query, 2, fixup_http_query_get,
130                 fixup_free_http_query_get,
131                 REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
132         {"http_client_query", (cmd_function)w_http_query_post, 3, fixup_http_query_post,
133                 fixup_free_http_query_post,
134                 REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
135         {"http_connect", (cmd_function)w_curl_connect, 3, fixup_curl_connect,
136                 fixup_free_curl_connect,
137                 REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
138         {"http_connect", (cmd_function)w_curl_connect_post, 5, fixup_curl_connect_post,
139                 fixup_free_curl_connect_post,
140                 REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
141         {"http_get_redirect", (cmd_function)w_curl_get_redirect, 2, fixup_curl_get_redirect,
142                 fixup_free_curl_get_redirect,
143                 REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
144         {"bind_http_client",  (cmd_function)bind_httpc_api,  0, 0, 0, 0},
145 };
146
147
148 /* Exported parameters */
149 static param_export_t params[] = {
150         {"connection_timeout", PARAM_INT, &default_connection_timeout},
151         {"cacert", PARAM_STRING,  &default_tls_cacert },
152         {"client_cert", PARAM_STR, &default_tls_clientcert },
153         {"client_key", PARAM_STR, &default_tls_clientkey },
154         {"cipher_suites", PARAM_STR, &default_cipher_suite_list },
155         {"tlsversion", PARAM_INT, &default_tls_version },
156         {"verify_peer", PARAM_INT, &default_tls_verify_peer },
157         {"verify_host", PARAM_INT, &default_tls_verify_host },
158         {"httpproxyport", PARAM_INT, &default_http_proxy_port },
159         {"httpproxy", PARAM_STR, &default_http_proxy},
160         {"httpredirect", PARAM_INT, &default_http_follow_redirect },
161         {"useragent", PARAM_STR,  &default_useragent },
162         {"maxdatasize", PARAM_INT,  &default_maxdatasize },
163         {"config_file", PARAM_STR,  &http_client_config_file },
164         {"httpcon",  PARAM_STRING|USE_FUNC_PARAM, (void*)curl_con_param},
165         {"authmetod", PARAM_INT, &default_authmethod },
166         {"keep_connections", PARAM_INT, &default_keep_connections },
167         {0, 0, 0}
168 };
169
170
171 /*!
172  * \brief Exported Pseudo variables
173  */
174 static pv_export_t mod_pvs[] = {
175         {{"curlerror", (sizeof("curlerror")-1)}, /* Curl error codes */
176         PVT_OTHER, pv_get_curlerror, 0, pv_parse_curlerror, 0, 0, 0},
177
178         {{0, 0}, 0, 0, 0, 0, 0, 0, 0}
179 };
180
181 /* Module interface */
182 struct module_exports exports = {
183         "http_client",
184         DEFAULT_DLFLAGS, /* dlopen flags */
185         cmds,      /* Exported functions */
186         params,    /* Exported parameters */
187         0,         /* exported statistics */
188         0,      /* exported MI functions */
189         mod_pvs,         /* exported pseudo-variables */
190         0,         /* extra processes */
191         mod_init,  /* module initialization function */
192         0,         /* response function*/
193         destroy,   /* destroy function */
194         child_init /* per-child init function */
195 };
196
197 counter_handle_t connections;   /* Number of connection definitions */
198 counter_handle_t connok;        /* Successful Connection attempts */
199 counter_handle_t connfail;      /* Failed Connection attempts */
200
201
202
203 static int init_shmlock(void)
204 {
205         return 0;
206 }
207
208
209 static void destroy_shmlock(void)
210 {
211         ;
212 }
213
214 /* Init counters */
215 static void curl_counter_init()
216 {
217         counter_register(&connections, "httpclient", "connections", 0, 0, 0, "Counter of connection definitions (httpcon)", 0);
218         counter_register(&connok, "httpclient", "connok", 0, 0, 0, "Counter of successful connections (200 OK)", 0);
219         counter_register(&connfail, "httpclient", "connfail", 0, 0, 0, "Counter of failed connections (not 200 OK)", 0);
220 }
221
222
223 /* Module initialization function */
224 static int mod_init(void)
225 {
226         
227         LM_DBG("init curl module\n");
228
229         /* Initialize curl */
230         if (curl_global_init(CURL_GLOBAL_ALL)) {
231                 LM_ERR("curl_global_init failed\n");
232                 return -1;
233         }
234         curl_info = curl_version_info(CURLVERSION_NOW);
235
236         if(curl_init_rpc() < 0)
237         {
238                 LM_ERR("failed to register RPC commands\n");
239                 return -1;
240         }
241
242         if (init_shmlock() != 0) {
243                 LM_CRIT("cannot initialize shmlock.\n");
244                 return -1;
245         }
246
247         curl_counter_init();
248         counter_add(connections, curl_connection_count());
249
250         if (default_tls_version >= CURL_SSLVERSION_LAST) {
251                 LM_WARN("tlsversion %d unsupported value. Using libcurl default\n", default_tls_version);
252                 default_tls_version = CURL_SSLVERSION_DEFAULT;
253         }
254         if (http_client_config_file.s != NULL)
255         {
256                 if (http_client_load_config(&http_client_config_file) < 0)
257                 {
258                         LM_ERR("Failed to load http_client connections from [%.*s]\n", http_client_config_file.len, http_client_config_file.s);
259                         return -1;
260                 }
261         }
262
263         if (default_connection_timeout == 0) {
264                 LM_ERR("CURL connection timeout set to zero. Using default 4 secs\n");
265                 default_connection_timeout = 4;
266         }
267         if (default_http_proxy_port == 0) {
268                 LM_INFO("HTTP proxy port set to 0. Disabling HTTP proxy\n");
269         }
270
271
272         LM_DBG("**** init curl module done. Curl version: %s SSL %s\n", curl_info->version, curl_info->ssl_version);
273         LM_DBG("**** init curl: Number of connection objects: %d \n", curl_connection_count());
274         LM_DBG("**** init curl: User Agent: %.*s \n", default_useragent.len, default_useragent.s);
275         LM_DBG("**** init curl: HTTPredirect: %d \n", default_http_follow_redirect);
276         LM_DBG("**** init curl: Client Cert: %.*s Key %.*s\n", default_tls_clientcert.len, default_tls_clientcert.s, default_tls_clientkey.len, default_tls_clientkey.s);
277         LM_DBG("**** init curl: CA Cert: %s \n", default_tls_cacert);
278         LM_DBG("**** init curl: Cipher Suites: %.*s \n", default_cipher_suite_list.len, default_cipher_suite_list.s);
279         LM_DBG("**** init curl: SSL Version: %d \n", default_tls_version);
280         LM_DBG("**** init curl: verifypeer: %d verifyhost: %d\n", default_tls_verify_peer, default_tls_verify_host);
281         LM_DBG("**** init curl: HTTP Proxy: %.*s Port %d\n", default_http_proxy.len, default_http_proxy.s, default_http_proxy_port);
282         LM_DBG("**** init curl: Auth method: %d \n", default_authmethod);
283         LM_DBG("**** init curl: Keep Connections open: %d \n", default_keep_connections);
284
285         LM_DBG("Extra: Curl supports %s %s %s \n",
286                         (curl_info->features & CURL_VERSION_SSL ? "SSL" : ""),
287                         (curl_info->features & CURL_VERSION_IPV6 ? "IPv6" : ""),
288                         (curl_info->features & CURL_VERSION_IDN ? "IDN" : "")
289                  );
290         return 0;
291 }
292
293 /*! Returns TRUE if curl supports TLS */
294 int curl_support_tls()
295 {
296         return (curl_info->features & CURL_VERSION_SSL);
297 }
298
299 /*! Returns TRUE if curl supports IPv6 */
300 int curl_support_ipv6()
301 {
302         return (curl_info->features & CURL_VERSION_IPV6);
303 }
304
305
306 /* Child initialization function */
307 static int child_init(int rank)
308 {       
309         int i = my_pid();
310
311         if (rank==PROC_INIT || rank==PROC_MAIN || rank==PROC_TCP_MAIN) {
312                 return 0; /* do nothing for the main process */
313         }
314         LM_DBG("*** http_client module initializing process %d\n", i);
315
316         return 0;
317 }
318
319
320 static void destroy(void)
321 {
322         /* Cleanup curl */
323         curl_global_cleanup();
324         destroy_shmlock();
325 }
326
327
328
329 /**
330  * parse httpcon module parameter
331  */
332 int curl_con_param(modparam_t type, void *val)
333 {
334         if(val == NULL) {
335                 goto error;
336         }
337
338         LM_DBG("**** HTTP_CLIENT got modparam httpcon \n");
339         return curl_parse_param((char*)val);
340 error:
341         return -1;
342
343 }
344
345 /* Fixup functions */
346
347 /*
348  * Fix http_query params: url (string that may contain pvars) and
349  * result (writable pvar).
350  */
351 static int fixup_http_query_get(void** param, int param_no)
352 {
353         if (param_no == 1) {
354                 return fixup_spve_null(param, 1);
355         }
356
357         if (param_no == 2) {
358                 if (fixup_pvar_null(param, 1) != 0) {
359                         LM_ERR("failed to fixup result pvar\n");
360                         return -1;
361                 }
362                 if (((pv_spec_t *)(*param))->setf == NULL) {
363                         LM_ERR("result pvar is not writeble\n");
364                         return -1;
365                 }
366                 return 0;
367         }
368
369         LM_ERR("invalid parameter number <%d>\n", param_no);
370         return -1;
371 }
372
373 /*
374  * Free http_query params.
375  */
376 static int fixup_free_http_query_get(void** param, int param_no)
377 {
378         if (param_no == 1) {
379                 return fixup_free_spve_null(param, 1);
380         }
381
382         if (param_no == 2) {
383         return fixup_free_pvar_null(param, 1);
384         }
385         
386         LM_ERR("invalid parameter number <%d>\n", param_no);
387         return -1;
388 }
389
390
391 /*
392  * Fix curl_connect params: connection(string/pvar) url (string that may contain pvars) and
393  * result (writable pvar).
394  */
395 static int fixup_curl_connect(void** param, int param_no)
396 {
397
398         if (param_no == 1) {
399         /* We want char * strings */
400                 return 0;
401         }
402         /* URL and data may contain pvar */
403         if (param_no == 2) {
404                 return fixup_spve_null(param, 1);
405         }
406         if (param_no == 3) {
407                 if (fixup_pvar_null(param, 1) != 0) {
408                         LM_ERR("failed to fixup result pvar\n");
409                         return -1;
410                 }
411                 if (((pv_spec_t *)(*param))->setf == NULL) {
412                         LM_ERR("result pvar is not writeble\n");
413                         return -1;
414                 }
415                 return 0;
416         }
417
418         LM_ERR("invalid parameter number <%d>\n", param_no);
419         return -1;
420 }
421
422 /*
423  * Fix curl_connect params when posting (5 parameters): 
424  *      connection (string/pvar), url (string with pvars), content-type, 
425  *      data (string/pvar, pvar)
426  */
427 static int fixup_curl_connect_post(void** param, int param_no)
428 {
429
430         if (param_no == 1 || param_no == 3) {
431                 /* We want char * strings */
432                 return 0;
433         }
434         /* URL and data may contain pvar */
435         if (param_no == 2 || param_no == 4) {
436                 return fixup_spve_null(param, 1);
437         }
438         if (param_no == 5) {
439                 if (fixup_pvar_null(param, 1) != 0) {
440                         LM_ERR("failed to fixup result pvar\n");
441                         return -1;
442                 }
443                 if (((pv_spec_t *)(*param))->setf == NULL) {
444                         LM_ERR("result pvar is not writeble\n");
445                         return -1;
446                 }
447                 return 0;
448         }
449
450         LM_ERR("invalid parameter number <%d>\n", param_no);
451         return -1;
452 }
453
454
455 /*
456  * Free curl_connect params.
457  */
458 static int fixup_free_curl_connect_post(void** param, int param_no)
459 {
460         if (param_no == 1 || param_no == 3) {
461                 /* Char strings don't need freeing */
462                 return 0;
463         }
464         if (param_no == 2 || param_no == 4) {
465                 return fixup_free_spve_null(param, 1);
466         }
467
468         if (param_no == 5) {
469                 return fixup_free_pvar_null(param, 1);
470         }
471         
472         LM_ERR("invalid parameter number <%d>\n", param_no);
473         return -1;
474 }
475
476 /*
477  * Free curl_connect params.
478  */
479 static int fixup_free_curl_connect(void** param, int param_no)
480 {
481         if (param_no == 1) {
482                 /* Char strings don't need freeing */
483                 return 0;
484         }
485         if (param_no == 2) {
486                 return fixup_free_spve_null(param, 1);
487         }
488
489         if (param_no == 3) {
490                 return fixup_free_pvar_null(param, 1);
491         }
492         
493         LM_ERR("invalid parameter number <%d>\n", param_no);
494         return -1;
495 }
496
497 /*
498  * Wrapper for Curl_connect (GET)
499  */
500 static int w_curl_connect(struct sip_msg* _m, char* _con, char * _url, char* _result) {
501
502         str con = {NULL,0};
503         str url = {NULL,0};
504         str result = {NULL,0};
505         pv_spec_t *dst;
506         pv_value_t val;
507         int ret = 0;
508
509         if (_con == NULL || _url == NULL || _result == NULL) {
510                 LM_ERR("Invalid parameter\n");
511         }
512         con.s = _con;
513         con.len = strlen(con.s);
514
515         if (get_str_fparam(&url, _m, (gparam_p)_url) != 0) {
516                 LM_ERR("_url has no value\n");
517                 return -1;
518         }
519
520         LM_DBG("**** Curl Connection %s URL %s Result var %s\n", _con, _url, _result);
521
522         ret = curl_con_query_url(_m, &con, &url, &result, NULL, NULL);
523
524         val.rs = result;
525         val.flags = PV_VAL_STR;
526         dst = (pv_spec_t *)_result;
527         dst->setf(_m, &dst->pvp, (int)EQ_T, &val);
528
529         if (result.s != NULL)
530                 pkg_free(result.s);
531
532         return ret;
533 }
534
535 /*
536  * Wrapper for Curl_connect (POST)
537  */
538 static int w_curl_connect_post(struct sip_msg* _m, char* _con, char * _url, char* _ctype, char* _data, char *_result) {
539         str con = {NULL,0};
540         str url = {NULL,0};
541         str data = {NULL, 0};
542         str result = {NULL,0};
543         pv_spec_t *dst;
544         pv_value_t val;
545         int ret = 0;
546
547         if (_con == NULL || _url == NULL || _data == NULL || _result == NULL) {
548                 LM_ERR("Invalid parameter\n");
549         }
550         con.s = _con;
551         con.len = strlen(con.s);
552
553         if (get_str_fparam(&url, _m, (gparam_p)_url) != 0) {
554                 LM_ERR("_url has no value\n");
555                 return -1;
556         }
557         if (get_str_fparam(&data, _m, (gparam_p)_data) != 0) {
558                 LM_ERR("_data has no value\n");
559                 return -1;
560         }
561
562         LM_DBG("**** Curl Connection %s URL %s Result var %s\n", _con, _url, _result);
563
564         ret = curl_con_query_url(_m, &con, &url, &result, _ctype, &data);
565
566         val.rs = result;
567         val.flags = PV_VAL_STR;
568         dst = (pv_spec_t *)_result;
569         dst->setf(_m, &dst->pvp, (int)EQ_T, &val);
570
571         if (result.s != NULL)
572                 pkg_free(result.s);
573
574         return ret;
575 }
576
577
578 /*!
579  * Fix http_query params: url (string that may contain pvars) and
580  * result (writable pvar).
581  */
582 static int fixup_http_query_post(void** param, int param_no)
583 {
584         if ((param_no == 1) || (param_no == 2)) {
585                 return fixup_spve_null(param, 1);
586         }
587
588         if (param_no == 3) {
589                 if (fixup_pvar_null(param, 1) != 0) {
590                         LM_ERR("failed to fixup result pvar\n");
591                         return -1;
592                 }
593                 if (((pv_spec_t *)(*param))->setf == NULL) {
594                         LM_ERR("result pvar is not writeble\n");
595                         return -1;
596                 }
597                 return 0;
598         }
599
600         LM_ERR("invalid parameter number <%d>\n", param_no);
601         return -1;
602 }
603
604 /*!
605  * Free http_query params.
606  */
607 static int fixup_free_http_query_post(void** param, int param_no)
608 {
609         if ((param_no == 1) || (param_no == 2)) {
610                 return fixup_free_spve_null(param, 1);
611         }
612
613         if (param_no == 3) {
614                 return fixup_free_pvar_null(param, 1);
615         }
616         
617         LM_ERR("invalid parameter number <%d>\n", param_no);
618         return -1;
619 }
620
621 /*!
622  * Wrapper for HTTP-Query (GET)
623  */
624 static int w_http_query(struct sip_msg* _m, char* _url, char* _result) {
625         int ret = 0;
626         str url = {NULL, 0};
627         str result = {NULL, 0};
628         pv_spec_t *dst;
629         pv_value_t val;
630
631         if (get_str_fparam(&url, _m, (gparam_p)_url) != 0) {
632                 LM_ERR("_url has no value\n");
633                 return -1;
634         }
635
636         ret = http_query(_m, url.s, &result, NULL);
637
638         val.rs = result;
639         val.flags = PV_VAL_STR;
640         dst = (pv_spec_t *)_result;
641         dst->setf(_m, &dst->pvp, (int)EQ_T, &val);
642
643         if (result.s != NULL)
644                 pkg_free(result.s);
645         return ret;
646 }
647
648
649 /*!
650  * Wrapper for HTTP-Query (POST-Variant)
651  */
652 static int w_http_query_post(struct sip_msg* _m, char* _url, char* _post, char* _result) {
653         int ret = 0;
654         str url = {NULL, 0};
655         str post = {NULL, 0};
656         str result = {NULL, 0};
657         pv_spec_t *dst;
658         pv_value_t val;
659
660         if (get_str_fparam(&url, _m, (gparam_p)_url) != 0) {
661                 LM_ERR("_url has no value\n");
662                 return -1;
663         }
664         if (get_str_fparam(&post, _m, (gparam_p)_post) != 0) {
665                 LM_ERR("_data has no value\n");
666                 return -1;
667         }
668
669         ret = http_query(_m, url.s, &result, post.s);
670         val.rs = result;
671         val.flags = PV_VAL_STR;
672         dst = (pv_spec_t *)_result;
673         dst->setf(_m, &dst->pvp, (int)EQ_T, &val);
674
675         if (result.s != NULL)
676                 pkg_free(result.s);
677         return ret;
678 }
679
680 /*!
681  * Parse arguments to  pv $curlerror
682  */
683 static int pv_parse_curlerror(pv_spec_p sp, str *in)
684 {
685         int cerr  = 0;
686         if(sp==NULL || in==NULL || in->len<=0)
687                 return -1;
688
689         
690         cerr = atoi(in->s);
691         LM_DBG(" =====> CURL ERROR %d \n", cerr);
692         sp->pvp.pvn.u.isname.name.n = cerr;
693
694         sp->pvp.pvn.type = PV_NAME_INTSTR;
695         sp->pvp.pvn.u.isname.type = 0;
696
697         return 0;
698 }
699
700 /*
701  * PV - return curl error explanation as string
702  */
703 static int pv_get_curlerror(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
704 {
705         str curlerr;
706         char *err = NULL;
707
708         if(param==NULL) {
709                 return -1;
710         }
711
712         /* cURL error codes does not collide with HTTP codes */
713         if (param->pvn.u.isname.name.n < 0 || param->pvn.u.isname.name.n > 999 ) {
714                 err = "Bad CURL error code";
715         }
716         if (param->pvn.u.isname.name.n > 99) {
717                 err = "HTTP result code";
718         }
719         if (err == NULL) {
720                 err = (char *) curl_easy_strerror(param->pvn.u.isname.name.n);
721         }
722         curlerr.s = err;
723         curlerr.len = strlen(err);
724
725         return pv_get_strval(msg, param, res, &curlerr);
726 }
727
728
729 /*
730  * Fix curl_get_redirect params: connection(string/pvar) url (string that may contain pvars) and
731  * result (writable pvar).
732  */
733 static int fixup_curl_get_redirect(void** param, int param_no)
734 {
735         if (param_no == 1) {    /* Connection name */
736                 /* We want char * strings */
737                 return 0;
738         }
739         if (param_no == 2) {    /* PVAR to store result in */
740                 if (fixup_pvar_null(param, 1) != 0) {
741                         LM_ERR("failed to fixup result pvar\n");
742                         return -1;
743                 }
744                 if (((pv_spec_t *)(*param))->setf == NULL) {
745                         LM_ERR("result pvar is not writeble\n");
746                         return -1;
747                 }
748                 return 0;
749         }
750
751         LM_ERR("invalid parameter number <%d>\n", param_no);
752         return -1;
753 }
754
755 /*
756  * Free curl_get_redirect params.
757  */
758 static int fixup_free_curl_get_redirect(void** param, int param_no)
759 {
760         if (param_no == 1) {
761                 /* Char strings don't need freeing */
762                 return 0;
763         }
764         if (param_no == 2) {
765                 return fixup_free_spve_null(param, 1);
766         }
767
768         LM_ERR("invalid parameter number <%d>\n", param_no);
769         return -1;
770 }
771
772 /*
773  * Wrapper for Curl_redirect
774  */
775 static int w_curl_get_redirect(struct sip_msg* _m, char* _con, char* _result) {
776
777         str con = {NULL,0};
778         str result = {NULL,0};
779         pv_spec_t *dst;
780         pv_value_t val;
781         int ret = 0;
782
783         if (_con == NULL || _result == NULL) {
784                 LM_ERR("Invalid parameter\n");
785         }
786         con.s = _con;
787         con.len = strlen(con.s);
788
789         LM_DBG("**** Curl Connection %s Result var %s\n", _con, _result);
790
791         ret = curl_get_redirect(_m, &con,  &result);
792
793         val.rs = result;
794         val.flags = PV_VAL_STR;
795         dst = (pv_spec_t *)_result;
796         dst->setf(_m, &dst->pvp, (int)EQ_T, &val);
797
798         if (result.s != NULL)
799                 pkg_free(result.s);
800
801         return ret;
802 }
803