1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 **/
19
20 #include "common.h"
21
22 #include "db.h"
23 #include "log.h"
24 #include "dbcache.h"
25
26 #include "zbxserver.h"
27 #include "httpmacro.h"
28 #include "httptest.h"
29 #include "zbxregexp.h"
30
31 typedef struct
32 {
33 char *data;
34 size_t allocated;
35 size_t offset;
36 }
37 zbx_httppage_t;
38
39 typedef struct
40 {
41 long rspcode;
42 double total_time;
43 double speed_download;
44 double test_total_time;
45 int test_last_step;
46 }
47 zbx_httpstat_t;
48
49 extern int CONFIG_HTTPPOLLER_FORKS;
50 extern char *CONFIG_SOURCE_IP;
51
52 #ifdef HAVE_LIBCURL
53
54 extern char *CONFIG_SSL_CA_LOCATION;
55 extern char *CONFIG_SSL_CERT_LOCATION;
56 extern char *CONFIG_SSL_KEY_LOCATION;
57
58 #define ZBX_RETRIEVE_MODE_CONTENT 0
59 #define ZBX_RETRIEVE_MODE_HEADERS 1
60
61 static zbx_httppage_t page;
62
WRITEFUNCTION2(void * ptr,size_t size,size_t nmemb,void * userdata)63 static size_t WRITEFUNCTION2(void *ptr, size_t size, size_t nmemb, void *userdata)
64 {
65 size_t r_size = size * nmemb;
66
67 /* first piece of data */
68 if (NULL == page.data)
69 {
70 page.allocated = MAX(8096, r_size);
71 page.offset = 0;
72 page.data = zbx_malloc(page.data, page.allocated);
73 }
74
75 zbx_strncpy_alloc(&page.data, &page.allocated, &page.offset, ptr, r_size);
76
77 return r_size;
78 }
79
HEADERFUNCTION2(void * ptr,size_t size,size_t nmemb,void * userdata)80 static size_t HEADERFUNCTION2(void *ptr, size_t size, size_t nmemb, void *userdata)
81 {
82 return size * nmemb;
83 }
84
85 #endif /* HAVE_LIBCURL */
86
87 /******************************************************************************
88 * *
89 * Function: httptest_remove_macros *
90 * *
91 * Purpose: remove all macro variables cached during http test execution *
92 * *
93 * Parameters: httptest - [IN] the http test data *
94 * *
95 * Author: Andris Zeila *
96 * *
97 ******************************************************************************/
httptest_remove_macros(zbx_httptest_t * httptest)98 static void httptest_remove_macros(zbx_httptest_t *httptest)
99 {
100 int i;
101
102 for (i = 0; i < httptest->macros.values_num; i++)
103 {
104 zbx_ptr_pair_t *pair = &httptest->macros.values[i];
105
106 zbx_free(pair->first);
107 zbx_free(pair->second);
108 }
109
110 zbx_vector_ptr_pair_clear(&httptest->macros);
111 }
112
process_test_data(zbx_uint64_t httptestid,int lastfailedstep,double speed_download,const char * err_str,zbx_timespec_t * ts)113 static void process_test_data(zbx_uint64_t httptestid, int lastfailedstep, double speed_download,
114 const char *err_str, zbx_timespec_t *ts)
115 {
116 const char *__function_name = "process_test_data";
117
118 DB_RESULT result;
119 DB_ROW row;
120 unsigned char types[3];
121 DC_ITEM items[3];
122 zbx_uint64_t itemids[3];
123 int errcodes[3];
124 size_t i, num = 0;
125 AGENT_RESULT value;
126
127 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
128
129 result = DBselect("select type,itemid from httptestitem where httptestid=" ZBX_FS_UI64, httptestid);
130
131 while (NULL != (row = DBfetch(result)))
132 {
133 if (3 == num)
134 {
135 THIS_SHOULD_NEVER_HAPPEN;
136 break;
137 }
138
139 switch (types[num] = (unsigned char)atoi(row[0]))
140 {
141 case ZBX_HTTPITEM_TYPE_SPEED:
142 case ZBX_HTTPITEM_TYPE_LASTSTEP:
143 break;
144 case ZBX_HTTPITEM_TYPE_LASTERROR:
145 if (NULL == err_str)
146 continue;
147 break;
148 default:
149 THIS_SHOULD_NEVER_HAPPEN;
150 continue;
151 }
152
153 ZBX_STR2UINT64(itemids[num], row[1]);
154 num++;
155 }
156 DBfree_result(result);
157
158 DCconfig_get_items_by_itemids(items, itemids, errcodes, num);
159
160 for (i = 0; i < num; i++)
161 {
162 if (SUCCEED != errcodes[i])
163 continue;
164
165 if (ITEM_STATUS_ACTIVE != items[i].status)
166 continue;
167
168 if (HOST_STATUS_MONITORED != items[i].host.status)
169 continue;
170
171 if (HOST_MAINTENANCE_STATUS_ON == items[i].host.maintenance_status &&
172 MAINTENANCE_TYPE_NODATA == items[i].host.maintenance_type)
173 {
174 continue;
175 }
176
177 init_result(&value);
178
179 switch (types[i])
180 {
181 case ZBX_HTTPITEM_TYPE_SPEED:
182 SET_UI64_RESULT(&value, speed_download);
183 break;
184 case ZBX_HTTPITEM_TYPE_LASTSTEP:
185 SET_UI64_RESULT(&value, lastfailedstep);
186 break;
187 case ZBX_HTTPITEM_TYPE_LASTERROR:
188 SET_STR_RESULT(&value, zbx_strdup(NULL, err_str));
189 break;
190 }
191
192 items[i].state = ITEM_STATE_NORMAL;
193 dc_add_history(items[i].itemid, items[i].value_type, 0, &value, ts, items[i].state, NULL);
194
195 free_result(&value);
196 }
197
198 DCconfig_clean_items(items, errcodes, num);
199
200 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
201 }
202
203 #ifdef HAVE_LIBCURL
process_step_data(zbx_uint64_t httpstepid,zbx_httpstat_t * stat,zbx_timespec_t * ts)204 static void process_step_data(zbx_uint64_t httpstepid, zbx_httpstat_t *stat, zbx_timespec_t *ts)
205 {
206 const char *__function_name = "process_step_data";
207
208 DB_RESULT result;
209 DB_ROW row;
210 unsigned char types[3];
211 DC_ITEM items[3];
212 zbx_uint64_t itemids[3];
213 int errcodes[3];
214 size_t i, num = 0;
215 AGENT_RESULT value;
216
217 zabbix_log(LOG_LEVEL_DEBUG, "In %s() rspcode:%ld time:" ZBX_FS_DBL " speed:" ZBX_FS_DBL,
218 __function_name, stat->rspcode, stat->total_time, stat->speed_download);
219
220 result = DBselect("select type,itemid from httpstepitem where httpstepid=" ZBX_FS_UI64, httpstepid);
221
222 while (NULL != (row = DBfetch(result)))
223 {
224 if (3 == num)
225 {
226 THIS_SHOULD_NEVER_HAPPEN;
227 break;
228 }
229
230 if (ZBX_HTTPITEM_TYPE_RSPCODE != (types[num] = (unsigned char)atoi(row[0])) &&
231 ZBX_HTTPITEM_TYPE_TIME != types[num] && ZBX_HTTPITEM_TYPE_SPEED != types[num])
232 {
233 THIS_SHOULD_NEVER_HAPPEN;
234 continue;
235 }
236
237 ZBX_STR2UINT64(itemids[num], row[1]);
238 num++;
239 }
240 DBfree_result(result);
241
242 DCconfig_get_items_by_itemids(items, itemids, errcodes, num);
243
244 for (i = 0; i < num; i++)
245 {
246 if (SUCCEED != errcodes[i])
247 continue;
248
249 if (ITEM_STATUS_ACTIVE != items[i].status)
250 continue;
251
252 if (HOST_STATUS_MONITORED != items[i].host.status)
253 continue;
254
255 if (HOST_MAINTENANCE_STATUS_ON == items[i].host.maintenance_status &&
256 MAINTENANCE_TYPE_NODATA == items[i].host.maintenance_type)
257 {
258 continue;
259 }
260
261 init_result(&value);
262
263 switch (types[i])
264 {
265 case ZBX_HTTPITEM_TYPE_RSPCODE:
266 SET_UI64_RESULT(&value, stat->rspcode);
267 break;
268 case ZBX_HTTPITEM_TYPE_TIME:
269 SET_DBL_RESULT(&value, stat->total_time);
270 break;
271 case ZBX_HTTPITEM_TYPE_SPEED:
272 SET_DBL_RESULT(&value, stat->speed_download);
273 break;
274 }
275
276 items[i].state = ITEM_STATE_NORMAL;
277 dc_add_history(items[i].itemid, items[i].value_type, 0, &value, ts, items[i].state, NULL);
278
279 free_result(&value);
280 }
281
282 DCconfig_clean_items(items, errcodes, num);
283
284 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
285 }
286
add_headers(char * headers,struct curl_slist ** headers_slist)287 static void add_headers(char *headers, struct curl_slist **headers_slist)
288 {
289 char *p_begin;
290
291 p_begin = headers;
292
293 while ('\0' != *p_begin)
294 {
295 char c, *p_end, *line;
296
297 while ('\r' == *p_begin || '\n' == *p_begin)
298 p_begin++;
299
300 p_end = p_begin;
301
302 while ('\0' != *p_end && '\r' != *p_end && '\n' != *p_end)
303 p_end++;
304
305 if (p_begin == p_end)
306 break;
307
308 if ('\0' != (c = *p_end))
309 *p_end = '\0';
310 line = zbx_strdup(NULL, p_begin);
311 if ('\0' != c)
312 *p_end = c;
313
314 zbx_lrtrim(line, " \t");
315 if ('\0' != *line)
316 *headers_slist = curl_slist_append(*headers_slist, line);
317 zbx_free(line);
318
319 p_begin = p_end;
320 }
321 }
322 #endif
323
324 /******************************************************************************
325 * *
326 * Function: process_httptest *
327 * *
328 * Purpose: process single scenario of http test *
329 * *
330 * Parameters: *
331 * *
332 * Return value: *
333 * *
334 * Author: Alexei Vladishev *
335 * *
336 * Comments: *
337 * *
338 ******************************************************************************/
process_httptest(DC_HOST * host,zbx_httptest_t * httptest)339 static void process_httptest(DC_HOST *host, zbx_httptest_t *httptest)
340 {
341 const char *__function_name = "process_httptest";
342
343 DB_RESULT result;
344 DB_HTTPSTEP httpstep;
345 char *err_str = NULL;
346 int lastfailedstep;
347 zbx_timespec_t ts;
348 double speed_download = 0;
349 int speed_download_num = 0;
350 #ifdef HAVE_LIBCURL
351 DB_ROW row;
352 zbx_httpstat_t stat;
353 int err;
354 char *auth = NULL, errbuf[CURL_ERROR_SIZE];
355 size_t auth_alloc = 0, auth_offset;
356 CURL *easyhandle = NULL;
357 #endif
358
359 zabbix_log(LOG_LEVEL_DEBUG, "In %s() httptestid:" ZBX_FS_UI64 " name:'%s'",
360 __function_name, httptest->httptest.httptestid, httptest->httptest.name);
361
362 lastfailedstep = 0;
363
364 result = DBselect(
365 "select httpstepid,no,name,url,timeout,posts,required,status_codes,variables,follow_redirects,"
366 "retrieve_mode,headers"
367 " from httpstep"
368 " where httptestid=" ZBX_FS_UI64
369 " order by no",
370 httptest->httptest.httptestid);
371
372 /* Explicitly initialize the name. If we compile without libCURL support, */
373 /* we avoid the potential usage of unititialized values. */
374 httpstep.name = NULL;
375
376 #ifdef HAVE_LIBCURL
377 if (NULL == (easyhandle = curl_easy_init()))
378 {
379 err_str = zbx_strdup(err_str, "cannot initialize cURL library");
380 goto clean;
381 }
382
383 if (CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_PROXY, httptest->httptest.http_proxy)) ||
384 CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_COOKIEFILE, "")) ||
385 CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_USERAGENT, httptest->httptest.agent)) ||
386 CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_WRITEFUNCTION, WRITEFUNCTION2)) ||
387 CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_HEADERFUNCTION, HEADERFUNCTION2)) ||
388 CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_SSL_VERIFYPEER,
389 0 == httptest->httptest.verify_peer ? 0L : 1L)) ||
390 CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_SSL_VERIFYHOST,
391 0 == httptest->httptest.verify_host ? 0L : 2L)) ||
392 CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_ERRORBUFFER, errbuf)))
393 {
394 err_str = zbx_strdup(err_str, curl_easy_strerror(err));
395 goto clean;
396 }
397
398 if (NULL != CONFIG_SOURCE_IP)
399 {
400 if (CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_INTERFACE, CONFIG_SOURCE_IP)))
401 {
402 err_str = zbx_strdup(err_str, curl_easy_strerror(err));
403 goto clean;
404 }
405 }
406
407 if (0 != httptest->httptest.verify_peer && NULL != CONFIG_SSL_CA_LOCATION)
408 {
409 if (CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_CAPATH, CONFIG_SSL_CA_LOCATION)))
410 {
411 err_str = zbx_strdup(err_str, curl_easy_strerror(err));
412 goto clean;
413 }
414 }
415
416 if ('\0' != *httptest->httptest.ssl_cert_file)
417 {
418 char *file_name;
419
420 file_name = zbx_dsprintf(NULL, "%s/%s", CONFIG_SSL_CERT_LOCATION, httptest->httptest.ssl_cert_file);
421 zabbix_log(LOG_LEVEL_DEBUG, "using SSL certificate file: '%s'", file_name);
422
423 err = curl_easy_setopt(easyhandle, CURLOPT_SSLCERT, file_name);
424 zbx_free(file_name);
425
426 if (CURLE_OK != err || CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_SSLCERTTYPE, "PEM")))
427 {
428 err_str = zbx_strdup(err_str, curl_easy_strerror(err));
429 goto clean;
430 }
431 }
432
433 if ('\0' != *httptest->httptest.ssl_key_file)
434 {
435 char *file_name;
436
437 file_name = zbx_dsprintf(NULL, "%s/%s", CONFIG_SSL_KEY_LOCATION, httptest->httptest.ssl_key_file);
438 zabbix_log(LOG_LEVEL_DEBUG, "using SSL private key file: '%s'", file_name);
439
440 err = curl_easy_setopt(easyhandle, CURLOPT_SSLKEY, file_name);
441 zbx_free(file_name);
442
443 if (CURLE_OK != err || CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_SSLKEYTYPE, "PEM")))
444 {
445 err_str = zbx_strdup(err_str, curl_easy_strerror(err));
446 goto clean;
447 }
448 }
449
450 if ('\0' != httptest->httptest.ssl_key_password)
451 {
452 if (CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_KEYPASSWD,
453 httptest->httptest.ssl_key_password)))
454 {
455 err_str = zbx_strdup(err_str, curl_easy_strerror(err));
456 goto clean;
457 }
458 }
459
460 while (NULL != (row = DBfetch(result)))
461 {
462 struct curl_slist *headers_slist = NULL;
463
464 /* NOTE: do not break or return from this block! */
465 /* process_step_data() call is required! */
466
467 ZBX_STR2UINT64(httpstep.httpstepid, row[0]);
468 httpstep.httptestid = httptest->httptest.httptestid;
469 httpstep.no = atoi(row[1]);
470 httpstep.name = row[2];
471
472 httpstep.url = zbx_strdup(NULL, row[3]);
473 substitute_simple_macros(NULL, NULL, NULL, NULL, NULL, host, NULL, NULL,
474 &httpstep.url, MACRO_TYPE_HTTPTEST_FIELD, NULL, 0);
475
476 httpstep.timeout = atoi(row[4]);
477
478 httpstep.posts = zbx_strdup(NULL, row[5]);
479 substitute_simple_macros(NULL, NULL, NULL, NULL, NULL, host, NULL, NULL,
480 &httpstep.posts, MACRO_TYPE_HTTPTEST_FIELD, NULL, 0);
481
482 httpstep.required = zbx_strdup(NULL, row[6]);
483 substitute_simple_macros(NULL, NULL, NULL, NULL, NULL, host, NULL, NULL,
484 &httpstep.required, MACRO_TYPE_HTTPTEST_FIELD, NULL, 0);
485
486 httpstep.status_codes = zbx_strdup(NULL, row[7]);
487 substitute_simple_macros(NULL, NULL, NULL, NULL, &host->hostid, NULL, NULL, NULL,
488 &httpstep.status_codes, MACRO_TYPE_COMMON, NULL, 0);
489
490 httpstep.variables = row[8];
491 httpstep.follow_redirects = atoi(row[9]);
492 httpstep.retrieve_mode = atoi(row[10]);
493
494 httpstep.headers = zbx_strdup(NULL, row[11]);
495 substitute_simple_macros(NULL, NULL, NULL, NULL, NULL, host, NULL, NULL,
496 &httpstep.headers, MACRO_TYPE_HTTPTEST_FIELD, NULL, 0);
497
498 memset(&stat, 0, sizeof(stat));
499
500 http_substitute_variables(httptest, &httpstep.url);
501 http_substitute_variables(httptest, &httpstep.posts);
502
503 zabbix_log(LOG_LEVEL_DEBUG, "%s() use step \"%s\"", __function_name, httpstep.name);
504
505 if (CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_POSTFIELDS, httpstep.posts)))
506 {
507 err_str = zbx_strdup(err_str, curl_easy_strerror(err));
508 goto httpstep_error;
509 }
510
511 if ('\0' != *httpstep.posts)
512 zabbix_log(LOG_LEVEL_DEBUG, "%s() use post \"%s\"", __function_name, httpstep.posts);
513
514 if (CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_POST, '\0' != *httpstep.posts ? 1L : 0L)))
515 {
516 err_str = zbx_strdup(err_str, curl_easy_strerror(err));
517 goto httpstep_error;
518 }
519
520 if (CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_FOLLOWLOCATION,
521 0 == httpstep.follow_redirects ? 0L : 1L)))
522 {
523 err_str = zbx_strdup(err_str, curl_easy_strerror(err));
524 goto httpstep_error;
525 }
526
527 if (0 != httpstep.follow_redirects)
528 {
529 if (CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_MAXREDIRS, ZBX_CURLOPT_MAXREDIRS)))
530 {
531 err_str = zbx_strdup(err_str, curl_easy_strerror(err));
532 goto httpstep_error;
533 }
534 }
535
536 http_substitute_variables(httptest, &httpstep.headers);
537
538 /* headers defined in a step overwrite headers defined in scenario */
539 if ('\0' != *httpstep.headers)
540 add_headers(httpstep.headers, &headers_slist);
541 else if ('\0' != *httptest->httptest.headers)
542 add_headers(httptest->httptest.headers, &headers_slist);
543
544 if (CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_HTTPHEADER, headers_slist)))
545 {
546 err_str = zbx_strdup(err_str, curl_easy_strerror(err));
547 goto httpstep_error;
548 }
549
550 /* enable/disable fetching the body */
551 if (CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_NOBODY,
552 ZBX_RETRIEVE_MODE_HEADERS == httpstep.retrieve_mode ? 1L : 0L)))
553 {
554 err_str = zbx_strdup(err_str, curl_easy_strerror(err));
555 goto httpstep_error;
556 }
557
558 if (HTTPTEST_AUTH_NONE != httptest->httptest.authentication)
559 {
560 long curlauth = 0;
561
562 zabbix_log(LOG_LEVEL_DEBUG, "%s() setting HTTPAUTH [%d]",
563 __function_name, httptest->httptest.authentication);
564 zabbix_log(LOG_LEVEL_DEBUG, "%s() setting USERPWD for authentication", __function_name);
565
566 switch (httptest->httptest.authentication)
567 {
568 case HTTPTEST_AUTH_BASIC:
569 curlauth = CURLAUTH_BASIC;
570 break;
571 case HTTPTEST_AUTH_NTLM:
572 curlauth = CURLAUTH_NTLM;
573 break;
574 default:
575 THIS_SHOULD_NEVER_HAPPEN;
576 break;
577 }
578
579 auth_offset = 0;
580 zbx_snprintf_alloc(&auth, &auth_alloc, &auth_offset, "%s:%s", httptest->httptest.http_user,
581 httptest->httptest.http_password);
582
583 if (CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_HTTPAUTH, curlauth)) ||
584 CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_USERPWD, auth)))
585 {
586 err_str = zbx_strdup(err_str, curl_easy_strerror(err));
587 goto httpstep_error;
588 }
589 }
590
591 zabbix_log(LOG_LEVEL_DEBUG, "%s() go to URL \"%s\"", __function_name, httpstep.url);
592
593 if (CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_TIMEOUT, (long)httpstep.timeout)) ||
594 CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_URL, httpstep.url)))
595 {
596 err_str = zbx_strdup(err_str, curl_easy_strerror(err));
597 goto httpstep_error;
598 }
599
600 /* try to retrieve page several times depending on number of retries */
601 do
602 {
603 memset(&page, 0, sizeof(page));
604
605 if (CURLE_OK == (err = curl_easy_perform(easyhandle)))
606 break;
607
608 zbx_free(page.data);
609 }
610 while (0 < --httptest->httptest.retries);
611
612 curl_slist_free_all(headers_slist); /* must be called after curl_easy_perform() */
613
614 if (CURLE_OK == err)
615 {
616 zabbix_log(LOG_LEVEL_TRACE, "%s() page.data from %s:'%s'", __function_name, httpstep.url, page.data);
617
618 /* first get the data that is needed even if step fails */
619 if (CURLE_OK != (err = curl_easy_getinfo(easyhandle, CURLINFO_RESPONSE_CODE, &stat.rspcode)))
620 {
621 err_str = zbx_strdup(err_str, curl_easy_strerror(err));
622 }
623 else if ('\0' != *httpstep.status_codes &&
624 FAIL == int_in_list(httpstep.status_codes, stat.rspcode))
625 {
626 err_str = zbx_dsprintf(err_str, "response code \"%ld\" did not match any of the"
627 " required status codes \"%s\"", stat.rspcode, httpstep.status_codes);
628 }
629
630 if (CURLE_OK != (err = curl_easy_getinfo(easyhandle, CURLINFO_TOTAL_TIME, &stat.total_time)) &&
631 NULL == err_str)
632 {
633 err_str = zbx_strdup(err_str, curl_easy_strerror(err));
634 }
635
636 if (CURLE_OK != (err = curl_easy_getinfo(easyhandle, CURLINFO_SPEED_DOWNLOAD,
637 &stat.speed_download)) && NULL == err_str)
638 {
639 err_str = zbx_strdup(err_str, curl_easy_strerror(err));
640 }
641 else
642 {
643 speed_download += stat.speed_download;
644 speed_download_num++;
645 }
646
647 if (ZBX_RETRIEVE_MODE_CONTENT == httpstep.retrieve_mode)
648 {
649 char *var_err_str = NULL;
650
651 /* required pattern */
652 if (NULL == err_str && '\0' != *httpstep.required && NULL == zbx_regexp_match(page.data,
653 httpstep.required, NULL))
654 {
655 err_str = zbx_dsprintf(err_str, "required pattern \"%s\" was not found on %s",
656 httpstep.required, httpstep.url);
657 }
658
659 /* variables defined in scenario */
660 if (NULL == err_str && FAIL == http_process_variables(httptest,
661 httptest->httptest.variables, page.data, &var_err_str))
662 {
663 char *variables;
664
665 variables = string_replace(httptest->httptest.variables, "\r\n", " ");
666 err_str = zbx_dsprintf(err_str, "error in scenario variables \"%s\": %s",
667 variables, var_err_str);
668
669 zbx_free(variables);
670 }
671
672 /* variables defined in a step */
673 if (NULL == err_str && FAIL == http_process_variables(httptest, httpstep.variables,
674 page.data, &var_err_str))
675 {
676 char *variables;
677
678 variables = string_replace(httpstep.variables, "\r\n", " ");
679 err_str = zbx_dsprintf(err_str, "error in step variables \"%s\": %s",
680 variables, var_err_str);
681
682 zbx_free(variables);
683 }
684
685 zbx_free(var_err_str);
686 }
687
688 zbx_timespec(&ts);
689 process_step_data(httpstep.httpstepid, &stat, &ts);
690
691 zbx_free(page.data);
692 }
693 else
694 err_str = zbx_dsprintf(err_str, "%s: %s", curl_easy_strerror(err), errbuf);
695
696 httpstep_error:
697 zbx_free(httpstep.headers);
698 zbx_free(httpstep.status_codes);
699 zbx_free(httpstep.required);
700 zbx_free(httpstep.posts);
701 zbx_free(httpstep.url);
702
703 if (NULL != err_str)
704 {
705 lastfailedstep = httpstep.no;
706 break;
707 }
708 }
709
710 zbx_free(auth);
711 clean:
712 curl_easy_cleanup(easyhandle);
713 #else
714 err_str = zbx_strdup(err_str, "cURL library is required for Web monitoring support");
715 #endif /* HAVE_LIBCURL */
716
717 zbx_timespec(&ts);
718
719 if (NULL != err_str)
720 {
721 if (0 == lastfailedstep)
722 {
723 /* we are here either because cURL initialization failed */
724 /* or we have been compiled without cURL library */
725
726 lastfailedstep = 1;
727 }
728
729 if (NULL != httpstep.name)
730 {
731 zabbix_log(LOG_LEVEL_DEBUG, "cannot process step \"%s\" of web scenario \"%s\" on host \"%s\": %s",
732 httpstep.name, httptest->httptest.name, host->name, err_str);
733 }
734 }
735 DBfree_result(result);
736
737 DBexecute("update httptest set nextcheck=%d+delay where httptestid=" ZBX_FS_UI64,
738 ts.sec, httptest->httptest.httptestid);
739
740 if (0 != speed_download_num)
741 speed_download /= speed_download_num;
742
743 process_test_data(httptest->httptest.httptestid, lastfailedstep, speed_download, err_str, &ts);
744
745 zbx_free(err_str);
746
747 dc_flush_history();
748
749 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
750 }
751
752 /******************************************************************************
753 * *
754 * Function: process_httptests *
755 * *
756 * Purpose: process httptests *
757 * *
758 * Parameters: now - current timestamp *
759 * *
760 * Return value: number of processed httptests *
761 * *
762 * Author: Alexei Vladishev *
763 * *
764 * Comments: always SUCCEED *
765 * *
766 ******************************************************************************/
process_httptests(int httppoller_num,int now)767 int process_httptests(int httppoller_num, int now)
768 {
769 const char *__function_name = "process_httptests";
770
771 DB_RESULT result;
772 DB_ROW row;
773 zbx_httptest_t httptest;
774 DC_HOST host;
775 int httptests_count = 0;
776
777 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
778
779 /* create macro cache to use in http tests */
780 zbx_vector_ptr_pair_create(&httptest.macros);
781
782 result = DBselect(
783 "select h.hostid,h.host,h.name,t.httptestid,t.name,t.variables,t.headers,t.agent,"
784 "t.authentication,t.http_user,t.http_password,t.http_proxy,t.retries,t.ssl_cert_file,"
785 "t.ssl_key_file,t.ssl_key_password,t.verify_peer,t.verify_host"
786 " from httptest t,hosts h"
787 " where t.hostid=h.hostid"
788 " and t.nextcheck<=%d"
789 " and " ZBX_SQL_MOD(t.httptestid,%d) "=%d"
790 " and t.status=%d"
791 " and h.proxy_hostid is null"
792 " and h.status=%d"
793 " and (h.maintenance_status=%d or h.maintenance_type=%d)",
794 now,
795 CONFIG_HTTPPOLLER_FORKS, httppoller_num - 1,
796 HTTPTEST_STATUS_MONITORED,
797 HOST_STATUS_MONITORED,
798 HOST_MAINTENANCE_STATUS_OFF, MAINTENANCE_TYPE_NORMAL);
799
800 while (NULL != (row = DBfetch(result)))
801 {
802 ZBX_STR2UINT64(host.hostid, row[0]);
803 strscpy(host.host, row[1]);
804 zbx_strlcpy_utf8(host.name, row[2], sizeof(host.name));
805
806 ZBX_STR2UINT64(httptest.httptest.httptestid, row[3]);
807 httptest.httptest.name = row[4];
808
809 httptest.httptest.variables = zbx_strdup(NULL, row[5]);
810 substitute_simple_macros(NULL, NULL, NULL, NULL, NULL, &host, NULL, NULL,
811 &httptest.httptest.variables, MACRO_TYPE_HTTPTEST_FIELD, NULL, 0);
812
813 httptest.httptest.headers = zbx_strdup(NULL, row[6]);
814 substitute_simple_macros(NULL, NULL, NULL, NULL, NULL, &host, NULL, NULL,
815 &httptest.httptest.headers, MACRO_TYPE_HTTPTEST_FIELD, NULL, 0);
816
817 httptest.httptest.agent = zbx_strdup(NULL, row[7]);
818 substitute_simple_macros(NULL, NULL, NULL, NULL, &host.hostid, NULL, NULL, NULL,
819 &httptest.httptest.agent, MACRO_TYPE_COMMON, NULL, 0);
820
821 if (HTTPTEST_AUTH_NONE != (httptest.httptest.authentication = atoi(row[8])))
822 {
823 httptest.httptest.http_user = zbx_strdup(NULL, row[9]);
824 substitute_simple_macros(NULL, NULL, NULL, NULL, &host.hostid, NULL, NULL, NULL,
825 &httptest.httptest.http_user, MACRO_TYPE_COMMON, NULL, 0);
826
827 httptest.httptest.http_password = zbx_strdup(NULL, row[10]);
828 substitute_simple_macros(NULL, NULL, NULL, NULL, &host.hostid, NULL, NULL, NULL,
829 &httptest.httptest.http_password, MACRO_TYPE_COMMON, NULL, 0);
830 }
831
832 if ('\0' != *row[11])
833 {
834 httptest.httptest.http_proxy = zbx_strdup(NULL, row[11]);
835 substitute_simple_macros(NULL, NULL, NULL, NULL, &host.hostid, NULL, NULL, NULL,
836 &httptest.httptest.http_proxy, MACRO_TYPE_COMMON, NULL, 0);
837 }
838 else
839 httptest.httptest.http_proxy = NULL;
840
841 httptest.httptest.retries = atoi(row[12]);
842
843 httptest.httptest.ssl_cert_file = zbx_strdup(NULL, row[13]);
844 substitute_simple_macros(NULL, NULL, NULL, NULL, NULL, &host, NULL, NULL,
845 &httptest.httptest.ssl_cert_file, MACRO_TYPE_HTTPTEST_FIELD, NULL, 0);
846
847 httptest.httptest.ssl_key_file = zbx_strdup(NULL, row[14]);
848 substitute_simple_macros(NULL, NULL, NULL, NULL, NULL, &host, NULL, NULL,
849 &httptest.httptest.ssl_key_file, MACRO_TYPE_HTTPTEST_FIELD, NULL, 0);
850
851 httptest.httptest.ssl_key_password = zbx_strdup(NULL, row[15]);
852 substitute_simple_macros(NULL, NULL, NULL, NULL, &host.hostid, NULL, NULL, NULL,
853 &httptest.httptest.ssl_key_password, MACRO_TYPE_COMMON, NULL, 0);
854
855 httptest.httptest.verify_peer = atoi(row[16]);
856 httptest.httptest.verify_host = atoi(row[17]);
857
858 /* add httptest variables to the current test macro cache */
859 http_process_variables(&httptest, httptest.httptest.variables, NULL, NULL);
860
861 process_httptest(&host, &httptest);
862
863 zbx_free(httptest.httptest.ssl_key_password);
864 zbx_free(httptest.httptest.ssl_key_file);
865 zbx_free(httptest.httptest.ssl_cert_file);
866 zbx_free(httptest.httptest.http_proxy);
867
868 if (HTTPTEST_AUTH_NONE != httptest.httptest.authentication)
869 {
870 zbx_free(httptest.httptest.http_password);
871 zbx_free(httptest.httptest.http_user);
872 }
873 zbx_free(httptest.httptest.agent);
874 zbx_free(httptest.httptest.headers);
875 zbx_free(httptest.httptest.variables);
876
877 /* clear the macro cache used in this http test */
878 httptest_remove_macros(&httptest);
879
880 httptests_count++; /* performance metric */
881 }
882 /* destroy the macro cache used in http tests */
883 zbx_vector_ptr_pair_destroy(&httptest.macros);
884
885 DBfree_result(result);
886
887 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
888
889 return httptests_count;
890 }
891