1 /**
2 * Copyright 2016 (C) Federico Cabiddu <federico.cabiddu@gmail.com>
3 * Copyright 2016 (C) Giacomo Vacca <giacomo.vacca@gmail.com>
4 * Copyright 2016 (C) Orange - Camille Oudot <camille.oudot@orange.com>
5 *
6 * This file is part of Kamailio, a free SIP server.
7 *
8 * This file is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version
12 *
13 *
14 * This file is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25 /*! \file
26 * \brief Kamailio http_async_client :: The module interface file
27 * \ingroup http_async_client
28 */
29
30 /*! \defgroup http_async_client Kamailio :: Async module interface to Curl/HTTP
31 *
32 * http://curl.haxx.se
33 * A generic library for many protocols
34 *
35 */
36
37 #include <stdio.h>
38 #include <unistd.h>
39 #include <stdlib.h>
40 #include <string.h>
41
42 #include "../../core/globals.h"
43 #include "../../core/sr_module.h"
44 #include "../../core/dprint.h"
45 #include "../../core/ut.h"
46 #include "../../core/pt.h"
47 #include "../../core/pvar.h"
48 #include "../../core/mem/shm_mem.h"
49 #include "../../core/mod_fix.h"
50 #include "../../core/pvar.h"
51 #include "../../core/cfg/cfg_struct.h"
52 #include "../../core/fmsg.h"
53 #include "../../core/kemi.h"
54
55 #include "../../modules/tm/tm_load.h"
56 #include "../../modules/pv/pv_api.h"
57
58
59 #include "async_http.h"
60
61 MODULE_VERSION
62
63 extern int num_workers;
64
65 extern unsigned int q_idx;
66 extern char q_id[MAX_ID_LEN+1];
67
68 int http_timeout = 500; /* query timeout in ms */
69 int tcp_keepalive = 0; /* TCP keepalives (default disabled) */
70 int tcp_ka_idle = 0; /* TCP keep-alive idle time wait */
71 int tcp_ka_interval = 0; /* TCP keep-alive interval */
72 int hash_size = 2048;
73 int tls_version = 0; // Use default SSL version in HTTPS requests (see curl/curl.h)
74 int tls_verify_host = 1; // By default verify host in HTTPS requests
75 int tls_verify_peer = 1; // By default verify peer in HTTPS requests
76 int curl_verbose = 0;
77 char* tls_client_cert = NULL; // client SSL certificate path, defaults to NULL
78 char* tls_client_key = NULL; // client SSL certificate key path, defaults to NULL
79 char* tls_ca_path = NULL; // certificate authority dir path, defaults to NULL
80 static char *memory_manager = "shm";
81 extern int curl_memory_manager;
82 unsigned int default_authmethod = CURLAUTH_BASIC | CURLAUTH_DIGEST;
83
84 static int mod_init(void);
85 static int child_init(int);
86 static void mod_destroy(void);
87
88 static int w_http_async_query(sip_msg_t* msg, char* query, char* rt);
89 static int set_query_param(str* param, str input);
90
91 /* pv api binding */
92 static int ah_get_reason(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
93 static int ah_get_hdr(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
94 static int w_pv_parse_hdr_name(pv_spec_p sp, str *in);
95 static int ah_get_status(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
96 static int ah_get_msg_body(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
97 static int ah_get_body_size(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
98 static int ah_get_msg_buf(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
99 static int ah_get_msg_len(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
100 static int ah_parse_req_name(pv_spec_p sp, str *in);
101 static int ah_set_req(struct sip_msg* msg, pv_param_t *param, int op, pv_value_t *val);
102 static int ah_get_id(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
103
104
105 static str pv_str_1 = {"1", 1};
106 static str pv_str_0 = {"0", 1};
107
108 static int ah_get_ok(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
109 static int ah_get_err(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
110
111 /* tm */
112 struct tm_binds tmb;
113 /* pv */
114 pv_api_t pv_api;
115
116 stat_var *requests;
117 stat_var *replies;
118 stat_var *errors;
119 stat_var *timeouts;
120
121 enum http_req_name_t {
122 E_HRN_ALL = 0,
123 E_HRN_HDR, E_HRN_METHOD, E_HRN_TIMEOUT,
124 E_HRN_TLS_CA_PATH, E_HRN_TLS_CLIENT_KEY,
125 E_HRN_TLS_CLIENT_CERT, E_HRN_SUSPEND,
126 E_HRN_BODY, E_HRN_AUTHMETHOD, E_HRN_USERNAME,
127 E_HRN_PASSWORD, E_HRN_TCP_KA, E_HRN_TCP_KA_IDLE,
128 E_HRN_TCP_KA_INTERVAL
129 };
130
131 static cmd_export_t cmds[]={
132 {"http_async_query", (cmd_function)w_http_async_query, 2, fixup_spve_spve,
133 0, ANY_ROUTE},
134 {0, 0, 0, 0, 0, 0}
135 };
136
137 static param_export_t params[]={
138 {"workers", INT_PARAM, &num_workers},
139 {"connection_timeout", INT_PARAM, &http_timeout},
140 {"hash_size", INT_PARAM, &hash_size},
141 {"tls_version", INT_PARAM, &tls_version},
142 {"tls_verify_host", INT_PARAM, &tls_verify_host},
143 {"tls_verify_peer", INT_PARAM, &tls_verify_peer},
144 {"curl_verbose", INT_PARAM, &curl_verbose},
145 {"tls_client_cert", PARAM_STRING, &tls_client_cert},
146 {"tls_client_key", PARAM_STRING, &tls_client_key},
147 {"tls_ca_path", PARAM_STRING, &tls_ca_path},
148 {"memory_manager", PARAM_STRING, &memory_manager},
149 {"authmethod", PARAM_INT, &default_authmethod },
150 {"tcp_keepalive", INT_PARAM, &tcp_keepalive},
151 {"tcp_ka_idle", INT_PARAM, &tcp_ka_idle},
152 {"tcp_ka_interval", INT_PARAM, &tcp_ka_interval},
153 {0, 0, 0}
154 };
155
156 /*! \brief We expose internal variables via the statistic framework below.*/
157 stat_export_t mod_stats[] = {
158 {"requests", STAT_NO_RESET, &requests },
159 {"replies", STAT_NO_RESET, &replies },
160 {"errors", STAT_NO_RESET, &errors },
161 {"timeouts", STAT_NO_RESET, &timeouts },
162 {0, 0, 0}
163 };
164
165 static pv_export_t pvs[] = {
166 {STR_STATIC_INIT("http_hdr"),
167 PVT_HDR, ah_get_hdr, 0,
168 w_pv_parse_hdr_name, pv_parse_index, 0, 0},
169 {STR_STATIC_INIT("http_rr"),
170 PVT_OTHER, ah_get_reason, 0,
171 0, 0, 0, 0},
172 {STR_STATIC_INIT("http_rs"),
173 PVT_OTHER, ah_get_status, 0,
174 0, 0, 0, 0},
175 {STR_STATIC_INIT("http_rb"),
176 PVT_MSG_BODY, ah_get_msg_body, 0,
177 0, 0, 0, 0},
178 {STR_STATIC_INIT("http_bs"),
179 PVT_OTHER, ah_get_body_size, 0,
180 0, 0, 0, 0},
181 {STR_STATIC_INIT("http_mb"),
182 PVT_OTHER, ah_get_msg_buf, 0,
183 0, 0, 0, 0},
184 {STR_STATIC_INIT("http_ml"),
185 PVT_OTHER, ah_get_msg_len, 0,
186 0, 0, 0, 0},
187 {STR_STATIC_INIT("http_ok"),
188 PVT_OTHER, ah_get_ok, 0,
189 0, 0, 0, 0},
190 {STR_STATIC_INIT("http_err"),
191 PVT_OTHER, ah_get_err, 0,
192 0, 0, 0, 0},
193 {STR_STATIC_INIT("http_req"),
194 PVT_OTHER, pv_get_null, ah_set_req,
195 ah_parse_req_name, 0, 0, 0},
196 {STR_STATIC_INIT("http_req_id"),
197 PVT_OTHER, ah_get_id, 0,
198 0, 0, 0, 0},
199 { {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
200 };
201
202 struct module_exports exports = {
203 "http_async_client", /* module name */
204 DEFAULT_DLFLAGS, /* dlopen flags */
205 cmds, /* exported functions */
206 params, /* exported parameters */
207 0, /* RPC method exports */
208 pvs, /* exported pseudo-variables */
209 0, /* response handling function */
210 mod_init, /* module initialization function */
211 child_init, /* per-child init function */
212 mod_destroy /* module destroy function */
213 };
214
215
216 /**
217 * init module function
218 */
mod_init(void)219 static int mod_init(void)
220 {
221 unsigned int n;
222 LM_INFO("Initializing Http Async module\n");
223
224 #ifdef STATISTICS
225 /* register statistics */
226 if (register_module_stats( exports.name, mod_stats)!=0 ) {
227 LM_ERR("failed to register core statistics\n");
228 return -1;
229 }
230 #endif
231 /* sanitize hash_size */
232 if (hash_size < 1){
233 LM_WARN("hash_size is smaller "
234 "than 1 -> rounding from %d to 1\n",
235 hash_size);
236 hash_size = 1;
237 }
238 /* check that the hash table size is a power of 2 */
239 for( n=0 ; n<(8*sizeof(n)) ; n++) {
240 if (hash_size==(1<<n))
241 break;
242 if (n && hash_size<(1<<n)) {
243 LM_WARN("hash_size is not a power "
244 "of 2 as it should be -> rounding from %d to %d (n=%d)\n",
245 hash_size, 1<<(n-1), n);
246 hash_size = 1<<(n-1);
247 break;
248 }
249 }
250 /* check 'workers' param */
251 if (num_workers < 1) {
252 LM_ERR("the 'workers' parameter must be >= 1\n");
253 return -1;
254 }
255
256 tls_verify_host = tls_verify_host?1:0;
257 tls_verify_peer = tls_verify_peer?1:0;
258
259 if (tcp_keepalive) {
260 LM_INFO("TCP keepalives enabled\n");
261 }
262 /* check tcp keepalive parameters */
263 if ((tcp_ka_idle > 0 || tcp_ka_interval > 0) && !(tcp_keepalive > 0)) {
264 LM_WARN("either 'tcp_ka_idle' or 'tcp_ka_interval' are set but 'tcp_keepalive' is disabled: they will be ignored\n");
265 }
266 /* init http parameters list */
267 init_query_params(&ah_params);
268
269 if (strncmp("shm", memory_manager, 3) == 0) {
270 curl_memory_manager = 0;
271 } else if (strncmp("sys", memory_manager, 3) == 0) {
272 curl_memory_manager = 1;
273 } else {
274 LM_ERR("invalid memory_manager parameter: '%s'\n", memory_manager);
275 return -1;
276 }
277
278 set_curl_mem_callbacks();
279
280 /* init faked sip msg */
281 if(faked_msg_init()<0) {
282 LM_ERR("failed to init faked sip msg\n");
283 return -1;
284 }
285
286 if(load_tm_api( &tmb ) < 0) {
287 LM_INFO("cannot load the TM-functions - async relay disabled\n");
288 memset(&tmb, 0, sizeof(tm_api_t));
289 }
290
291 /* allocate workers array */
292 workers = shm_malloc(num_workers * sizeof(*workers));
293 if(workers == NULL) {
294 LM_ERR("error in shm_malloc\n");
295 return -1;
296 }
297 memset(workers, 0, num_workers * sizeof(*workers));
298
299 register_procs(num_workers);
300
301 /* add child to update local config framework structures */
302 cfg_register_child(num_workers);
303
304 return 0;
305 }
306
307 /**
308 * @brief Initialize async module children
309 */
child_init(int rank)310 static int child_init(int rank)
311 {
312 int pid;
313 int i;
314
315 LM_DBG("child initializing async http\n");
316
317 if(num_workers<=0)
318 return 0;
319
320 /* initialize query counter and id */
321 q_idx = 0;
322 q_id[0] = '\0';
323
324 if (rank==PROC_INIT) {
325 for(i=0; i<num_workers; i++) {
326 LM_DBG("initializing worker notification socket: %d\n", i);
327 if(async_http_init_sockets(&workers[i])<0) {
328 LM_ERR("failed to initialize tasks sockets\n");
329 return -1;
330 }
331 }
332
333 return 0;
334 }
335
336 if(rank>0) {
337 for(i=0; i<num_workers; i++) {
338 close(workers[i].notication_socket[0]);
339 }
340 return 0;
341 }
342 if (rank!=PROC_MAIN)
343 return 0;
344
345 for(i=0; i<num_workers; i++) {
346 if(async_http_init_worker(i+1, &workers[i])<0) {
347 LM_ERR("failed to initialize worker process: %d\n", i);
348 return -1;
349 }
350 pid=fork_process(PROC_RPC, "Http Async Worker", 1);
351 if (pid<0)
352 return -1; /* error */
353 if(pid==0) {
354 /* child */
355 /* enforce http_reply_parse=yes */
356 http_reply_parse = 1;
357 /* initialize the config framework */
358 if (cfg_child_init())
359 return -1;
360 /* init msg structure for http reply parsing */
361 ah_reply = pkg_malloc(sizeof(struct sip_msg));
362 if(!ah_reply) {
363 LM_ERR("failed to allocate pkg memory\n");
364 return -1;
365 }
366 memset(ah_reply, 0, sizeof(struct sip_msg));
367 /* main function for workers */
368 async_http_run_worker(&workers[i]);
369 }
370 }
371
372 return 0;
373 }
374
375 /**
376 * destroy module function
377 */
mod_destroy(void)378 static void mod_destroy(void)
379 {
380 }
381
382 /**
383 *
384 */
w_http_async_query(sip_msg_t * msg,char * query,char * rt)385 static int w_http_async_query(sip_msg_t *msg, char *query, char* rt)
386 {
387 str sdata;
388 str rn;
389
390 if(msg==NULL)
391 return -1;
392
393 if(fixup_get_svalue(msg, (gparam_t*)query, &sdata)!=0) {
394 LM_ERR("unable to get data\n");
395 return -1;
396 }
397 if(sdata.s==NULL || sdata.len == 0) {
398 LM_ERR("invalid data parameter\n");
399 return -1;
400 }
401
402 if(fixup_get_svalue(msg, (gparam_t*)rt, &rn)!=0)
403 {
404 LM_ERR("no route block name\n");
405 return -1;
406 }
407 if(rn.s==NULL || rn.len == 0) {
408 LM_ERR("invalid route name parameter\n");
409 return -1;
410 }
411 return async_send_query(msg, &sdata, &rn);
412 }
413
414 /**
415 *
416 */
ki_http_async_query(sip_msg_t * msg,str * sdata,str * rn)417 static int ki_http_async_query(sip_msg_t *msg, str *sdata, str *rn)
418 {
419 if(msg==NULL)
420 return -1;
421 if(sdata==NULL || sdata->len <= 0) {
422 LM_ERR("invalid data parameter\n");
423 return -1;
424 }
425 if(rn->s==NULL || rn->len <= 0) {
426 LM_ERR("invalid route name parameter\n");
427 return -1;
428 }
429 return async_send_query(msg, sdata, rn);
430 }
431
432 #define _IVALUE_ERROR(NAME) LM_ERR("invalid parameter '" #NAME "' (must be a number)\n")
433 #define _IVALUE(NAME)\
434 int i_##NAME ;\
435 if(fixup_get_ivalue(msg, (gparam_t*)NAME, &( i_##NAME))!=0)\
436 { \
437 _IVALUE_ERROR(NAME);\
438 return -1;\
439 }
440 /*
441 * Helper to copy input string parameter into a query parameter
442 */
set_query_param(str * param,str input)443 static int set_query_param(str* param, str input)
444 {
445 if (param->s) {
446 shm_free(param->s);
447 param->s = NULL;
448 param->len = 0;
449 }
450
451 if (input.s && input.len > 0) {
452 if (shm_str_dup(param, &input) < 0) {
453 LM_ERR("Error allocating parameter\n");
454 return -1;
455 }
456 }
457
458 return 1;
459 }
460
461 /*
462 * Helper to copy input string parameter into a query char* parameter
463 */
set_query_cparam(char ** param,str input)464 static int set_query_cparam(char** param, str input)
465 {
466 if (*param) {
467 shm_free(*param);
468 *param = NULL;
469 }
470
471 if (input.s && input.len > 0) {
472 *param = shm_malloc(input.len+1);
473
474 if(*param == NULL) {
475 LM_ERR("error in shm_malloc\n");
476 return -1;
477 }
478
479 strncpy(*param, input.s, input.len);
480 (*param)[input.len] = '\0';
481
482 LM_DBG("param set to '%s'\n", *param);
483 }
484
485 return 1;
486 }
487
488 /* module PVs */
489
490 #define AH_WRAP_GET_PV(AH_F, PV_F) static int AH_F(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) \
491 { \
492 if (ah_reply) { \
493 if (ah_error.s) { \
494 LM_WARN("an async variable was read after http error, use $http_ok to check the request's status\n"); \
495 return pv_get_null(msg, param, res); \
496 } else { \
497 return pv_api.PV_F(ah_reply, param, res); \
498 } \
499 } else { \
500 LM_ERR("the async variables can only be read from an async http worker\n"); \
501 return pv_get_null(msg, param, res); \
502 } \
503 }
504
AH_WRAP_GET_PV(ah_get_reason,get_reason)505 AH_WRAP_GET_PV(ah_get_reason, get_reason)
506 AH_WRAP_GET_PV(ah_get_hdr, get_hdr)
507 AH_WRAP_GET_PV(ah_get_status, get_status)
508 AH_WRAP_GET_PV(ah_get_msg_body, get_msg_body)
509 AH_WRAP_GET_PV(ah_get_body_size, get_body_size)
510 AH_WRAP_GET_PV(ah_get_msg_buf, get_msg_buf)
511 AH_WRAP_GET_PV(ah_get_msg_len, get_msg_len)
512
513 static int w_pv_parse_hdr_name(pv_spec_p sp, str *in) {
514 return pv_api.parse_hdr_name(sp, in);
515 }
516
ah_get_id(struct sip_msg * msg,pv_param_t * param,pv_value_t * res)517 static int ah_get_id(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) {
518 return pv_get_strlval(msg, param, res, q_id, strlen(q_id));
519 }
520
ah_get_ok(struct sip_msg * msg,pv_param_t * param,pv_value_t * res)521 static int ah_get_ok(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) {
522 if (ah_reply) {
523 if (ah_error.s) {
524 return pv_get_intstrval(msg, param, res, 0, &pv_str_0);
525 } else {
526 return pv_get_intstrval(msg, param, res, 1, &pv_str_1);
527 }
528 } else {
529 LM_ERR("the async variables can only be read from an async http worker\n");
530 return pv_get_null(msg, param, res);
531 }
532 }
533
ah_get_err(struct sip_msg * msg,pv_param_t * param,pv_value_t * res)534 static int ah_get_err(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) {
535 if (ah_reply) {
536 if (ah_error.s) {
537 return pv_get_strval(msg, param, res, &ah_error);
538 } else {
539 return pv_get_null(msg, param, res);
540 }
541 } else {
542 LM_ERR("the async variables can only be read from an async http worker\n");
543 return pv_get_null(msg, param, res);
544 }
545 }
546
ah_parse_req_name(pv_spec_p sp,str * in)547 static int ah_parse_req_name(pv_spec_p sp, str *in) {
548 if(sp==NULL || in==NULL || in->len<=0)
549 return -1;
550
551 switch(in->len)
552 {
553 case 3:
554 if(strncmp(in->s, "all", 3)==0)
555 sp->pvp.pvn.u.isname.name.n = E_HRN_ALL;
556 else if(strncmp(in->s, "hdr", 3)==0)
557 sp->pvp.pvn.u.isname.name.n = E_HRN_HDR;
558 else goto error;
559 break;
560 case 4:
561 if(strncmp(in->s, "body", 4)==0)
562 sp->pvp.pvn.u.isname.name.n = E_HRN_BODY;
563 else goto error;
564 break;
565 case 6:
566 if(strncmp(in->s, "method", 6)==0)
567 sp->pvp.pvn.u.isname.name.n = E_HRN_METHOD;
568 else goto error;
569 break;
570 case 7:
571 if(strncmp(in->s, "timeout", 7)==0)
572 sp->pvp.pvn.u.isname.name.n = E_HRN_TIMEOUT;
573 else if(strncmp(in->s, "suspend", 7)==0)
574 sp->pvp.pvn.u.isname.name.n = E_HRN_SUSPEND;
575 else if(strncmp(in->s, "ka-idle", 7)==0)
576 sp->pvp.pvn.u.isname.name.n = E_HRN_TCP_KA_IDLE;
577 else goto error;
578 break;
579 case 8:
580 if(strncmp(in->s, "username", 8)==0)
581 sp->pvp.pvn.u.isname.name.n = E_HRN_USERNAME;
582 else if(strncmp(in->s, "password", 8)==0)
583 sp->pvp.pvn.u.isname.name.n = E_HRN_PASSWORD;
584 else goto error;
585 break;
586 case 9:
587 if(strncmp(in->s, "keepalive", 9)==0)
588 sp->pvp.pvn.u.isname.name.n = E_HRN_TCP_KA;
589 else goto error;
590 break;
591 case 10:
592 if(strncmp(in->s, "authmethod", 10)==0)
593 sp->pvp.pvn.u.isname.name.n = E_HRN_AUTHMETHOD;
594 else goto error;
595 break;
596 case 11:
597 if(strncmp(in->s, "tls_ca_path", 11)==0)
598 sp->pvp.pvn.u.isname.name.n = E_HRN_TLS_CA_PATH;
599 else if(strncmp(in->s, "ka-interval", 11)==0)
600 sp->pvp.pvn.u.isname.name.n = E_HRN_TCP_KA_INTERVAL;
601 else goto error;
602 break;
603 case 14:
604 if(strncmp(in->s, "tls_client_key", 14)==0)
605 sp->pvp.pvn.u.isname.name.n = E_HRN_TLS_CLIENT_KEY;
606 else goto error;
607 break;
608 case 15:
609 if(strncmp(in->s, "tls_client_cert", 15)==0)
610 sp->pvp.pvn.u.isname.name.n = E_HRN_TLS_CLIENT_CERT;
611 else goto error;
612 break;
613 default:
614 goto error;
615 }
616 sp->pvp.pvn.type = PV_NAME_INTSTR;
617 sp->pvp.pvn.u.isname.type = 0;
618
619 return 0;
620
621 error:
622 LM_ERR("unknown http_req name %.*s\n", in->len, in->s);
623 return -1;
624 }
625
ah_set_req(struct sip_msg * msg,pv_param_t * param,int op,pv_value_t * val)626 static int ah_set_req(struct sip_msg* msg, pv_param_t *param,
627 int op, pv_value_t *val)
628 {
629 pv_value_t *tval;
630
631 if(param==NULL || tmb.t_request==NULL)
632 return -1;
633
634 tval = val;
635 if((tval!=NULL) && (tval->flags&PV_VAL_NULL)) {
636 tval = NULL;
637 }
638
639 switch((enum http_req_name_t) param->pvn.u.isname.name.n) {
640 case E_HRN_ALL:
641 if (tval == NULL)
642 set_query_params(&ah_params);
643 break;
644 case E_HRN_HDR:
645 if (tval) {
646 if (!(tval->flags & PV_VAL_STR)) {
647 LM_ERR("invalid value type for $http_req(hdr)\n");
648 return -1;
649 }
650 header_list_add(&ah_params.headers, &tval->rs);
651 }
652 break;
653 case E_HRN_METHOD:
654 if (tval) {
655 if (!(tval->flags & PV_VAL_STR)) {
656 LM_ERR("invalid value type for $http_req(method)\n");
657 return -1;
658 }
659 query_params_set_method(&ah_params, &tval->rs);
660 } else {
661 ah_params.method = AH_METH_DEFAULT;
662 }
663 break;
664 case E_HRN_TIMEOUT:
665 if (tval) {
666 if (!(tval->flags & PV_VAL_INT)) {
667 LM_ERR("invalid value type for $http_req(timeout)\n");
668 return -1;
669 }
670 ah_params.timeout = tval->ri;
671 } else {
672 ah_params.timeout = http_timeout;
673 }
674 break;
675 case E_HRN_TLS_CA_PATH:
676 if (tval) {
677 if (!(tval->flags & PV_VAL_STR)) {
678 LM_ERR("invalid value type for $http_req(tls_ca_path)\n");
679 return -1;
680 }
681 set_query_cparam(&ah_params.tls_ca_path, tval->rs);
682 }
683 break;
684 case E_HRN_TLS_CLIENT_KEY:
685 if (tval) {
686 if (!(tval->flags & PV_VAL_STR)) {
687 LM_ERR("invalid value type for $http_req(tls_client_key)\n");
688 return -1;
689 }
690 set_query_cparam(&ah_params.tls_client_key, tval->rs);
691 }
692 break;
693 case E_HRN_TLS_CLIENT_CERT:
694 if (tval) {
695 if (!(tval->flags & PV_VAL_STR)) {
696 LM_ERR("invalid value type for $http_req(tls_client_cert)\n");
697 return -1;
698 }
699 set_query_cparam(&ah_params.tls_client_cert, tval->rs);
700 }
701 break;
702 case E_HRN_SUSPEND:
703 if (tval) {
704 if (!(tval->flags & PV_VAL_INT)) {
705 LM_ERR("invalid value type for $http_req(suspend)\n");
706 return -1;
707 }
708 ah_params.suspend_transaction = tval->ri?1:0;
709 } else {
710 ah_params.suspend_transaction = 1;
711 }
712 break;
713 case E_HRN_BODY:
714 if (tval) {
715 if (!(tval->flags & PV_VAL_STR)) {
716 LM_ERR("invalid value type for $http_req(body)\n");
717 return -1;
718 }
719 set_query_param(&ah_params.body, tval->rs);
720 }
721 break;
722 case E_HRN_AUTHMETHOD:
723 if (tval) {
724 if (!(tval->flags & PV_VAL_INT)) {
725 LM_ERR("invalid value type for $http_req(authmethod)\n");
726 return -1;
727 }
728 ah_params.authmethod = tval->ri;
729 } else {
730 ah_params.authmethod = default_authmethod;
731 }
732 break;
733 case E_HRN_USERNAME:
734 if (tval) {
735 if (!(tval->flags & PV_VAL_STR)) {
736 LM_ERR("invalid value type for $http_req(username)\n");
737 return -1;
738 }
739 set_query_cparam(&ah_params.username, tval->rs);
740 }
741 break;
742 case E_HRN_PASSWORD:
743 if (tval) {
744 if (!(tval->flags & PV_VAL_STR)) {
745 LM_ERR("invalid value type for $http_req(password)\n");
746 return -1;
747 }
748 set_query_cparam(&ah_params.password, tval->rs);
749 }
750 break;
751 case E_HRN_TCP_KA:
752 if (tval) {
753 if (!(tval->flags & PV_VAL_INT)) {
754 LM_ERR("invalid value type for $http_req(keepalive)\n");
755 return -1;
756 }
757 ah_params.tcp_keepalive = tval->ri;
758 } else {
759 ah_params.tcp_keepalive = tcp_keepalive;
760 }
761 break;
762
763 case E_HRN_TCP_KA_IDLE:
764 if (tval) {
765 if (!(tval->flags & PV_VAL_INT)) {
766 LM_ERR("invalid value type for $http_req(ka-idle)\n");
767 return -1;
768 }
769 ah_params.tcp_ka_idle = tval->ri;
770 } else {
771 ah_params.tcp_ka_idle = tcp_ka_idle;
772 }
773 break;
774
775 case E_HRN_TCP_KA_INTERVAL:
776 if (tval) {
777 if (!(tval->flags & PV_VAL_INT)) {
778 LM_ERR("invalid value type for $http_req(ka-interval)\n");
779 return -1;
780 }
781 ah_params.tcp_ka_interval = tval->ri;
782 } else {
783 ah_params.tcp_ka_interval = tcp_ka_interval;
784 }
785 break;
786 }
787
788 return 1;
789 }
790
791 /**
792 *
793 */
794 /* clang-format off */
795 static sr_kemi_t sr_kemi_http_async_client_exports[] = {
796 { str_init("http_async_client"), str_init("query"),
797 SR_KEMIP_INT, ki_http_async_query,
798 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
799 SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
800 },
801
802 { {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
803 };
804 /* clang-format on */
805
mod_register(char * path,int * dlflags,void * p1,void * p2)806 int mod_register(char *path, int *dlflags, void *p1, void *p2)
807 {
808 pv_register_api_t pvra;
809
810 pvra = (pv_register_api_t)find_export("pv_register_api", NO_SCRIPT, 0);
811 if (!pvra) {
812 LM_ERR("Cannot import pv functions (pv module must be loaded before this module)\n");
813 return -1;
814 }
815 pvra(&pv_api);
816 sr_kemi_modules_add(sr_kemi_http_async_client_exports);
817 return 0;
818 }
819