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 envied 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 #include "log.h"
22 #include "zbxjson.h"
23 #include "zbxhttp.h"
24 #include "zbxembed.h"
25 #include "httprequest.h"
26 #include "embed.h"
27 #include "duktape.h"
28 #include "zbxalgo.h"
29
30 #ifdef HAVE_LIBCURL
31
32 #define ZBX_HTTPAUTH_NONE CURLAUTH_NONE
33 #define ZBX_HTTPAUTH_BASIC CURLAUTH_BASIC
34 #define ZBX_HTTPAUTH_DIGEST CURLAUTH_DIGEST
35 #if LIBCURL_VERSION_NUM >= 0x072600
36 # define ZBX_HTTPAUTH_NEGOTIATE CURLAUTH_NEGOTIATE
37 #else
38 # define ZBX_HTTPAUTH_NEGOTIATE CURLAUTH_GSSNEGOTIATE
39 #endif
40 #define ZBX_HTTPAUTH_NTLM CURLAUTH_NTLM
41
42 extern char *CONFIG_SOURCE_IP;
43
44 typedef struct
45 {
46 CURL *handle;
47 struct curl_slist *headers;
48 char *data;
49 char *headers_in;
50 size_t data_alloc;
51 size_t data_offset;
52 size_t headers_in_alloc;
53 size_t headers_in_offset;
54 unsigned char custom_header;
55 }
56 zbx_es_httprequest_t;
57
58 /* ZBX_CURL_SETOPT() macro is a code snippet to make code shorter and facilitate resource deallocation */
59 /* in case of error. Be careful with using ZBX_CURL_SETOPT(), duk_push_error_object() and duk_error() */
60 /* in functions - it is easy to get memory leaks because duk_error() causes longjmp(). */
61 /* Note that the caller of ZBX_CURL_SETOPT() must define variable 'int err_index' and label 'out'. */
62 #define ZBX_CURL_SETOPT(ctx, handle, opt, value, err) \
63 if (CURLE_OK != (err = curl_easy_setopt(handle, opt, value))) \
64 { \
65 err_index = duk_push_error_object(ctx, DUK_RET_EVAL_ERROR, \
66 "cannot set cURL option " #opt ": %s.", curl_easy_strerror(err)); \
67 goto out; \
68 }
69
curl_write_cb(void * ptr,size_t size,size_t nmemb,void * userdata)70 static size_t curl_write_cb(void *ptr, size_t size, size_t nmemb, void *userdata)
71 {
72 size_t r_size = size * nmemb;
73 zbx_es_httprequest_t *request = (zbx_es_httprequest_t *)userdata;
74
75 zbx_strncpy_alloc(&request->data, &request->data_alloc, &request->data_offset, (const char *)ptr, r_size);
76
77 return r_size;
78 }
79
curl_header_cb(void * ptr,size_t size,size_t nmemb,void * userdata)80 static size_t curl_header_cb(void *ptr, size_t size, size_t nmemb, void *userdata)
81 {
82 size_t r_size = size * nmemb;
83 zbx_es_httprequest_t *request = (zbx_es_httprequest_t *)userdata;
84
85 zbx_strncpy_alloc(&request->headers_in, &request->headers_in_alloc, &request->headers_in_offset, (const char *)ptr, r_size);
86
87 return r_size;
88 }
89
90 /******************************************************************************
91 * *
92 * Function: es_httprequest *
93 * *
94 * Purpose: return backing C structure embedded in CurlHttpRequest object *
95 * *
96 ******************************************************************************/
es_httprequest(duk_context * ctx)97 static zbx_es_httprequest_t *es_httprequest(duk_context *ctx)
98 {
99 zbx_es_httprequest_t *request;
100
101 duk_push_this(ctx);
102 duk_get_prop_string(ctx, -1, "\xff""\xff""d");
103 request = (zbx_es_httprequest_t *)duk_to_pointer(ctx, -1);
104 duk_pop(ctx);
105
106 return request;
107 }
108
109 /******************************************************************************
110 * *
111 * Function: es_httprequest_dtor *
112 * *
113 * Purpose: CurlHttpRequest destructor *
114 * *
115 ******************************************************************************/
es_httprequest_dtor(duk_context * ctx)116 static duk_ret_t es_httprequest_dtor(duk_context *ctx)
117 {
118 zbx_es_httprequest_t *request;
119
120 duk_get_prop_string(ctx, 0, "\xff""\xff""d");
121 request = (zbx_es_httprequest_t *)duk_to_pointer(ctx, -1);
122 if (NULL != request)
123 {
124 if (NULL != request->headers)
125 curl_slist_free_all(request->headers);
126 if (NULL != request->handle)
127 curl_easy_cleanup(request->handle);
128 zbx_free(request->data);
129 zbx_free(request->headers_in);
130 zbx_free(request);
131
132 duk_push_pointer(ctx, NULL);
133 duk_put_prop_string(ctx, 0, "\xff""\xff""d");
134 }
135
136 return 0;
137 }
138
139 /******************************************************************************
140 * *
141 * Function: es_httprequest_ctor *
142 * *
143 * Purpose: CurlHttpRequest constructor *
144 * *
145 ******************************************************************************/
es_httprequest_ctor(duk_context * ctx)146 static duk_ret_t es_httprequest_ctor(duk_context *ctx)
147 {
148 zbx_es_httprequest_t *request;
149 CURLcode err;
150 zbx_es_env_t *env;
151 int err_index = -1;
152
153 if (!duk_is_constructor_call(ctx))
154 return DUK_RET_TYPE_ERROR;
155
156 duk_push_global_stash(ctx);
157
158 if (1 != duk_get_prop_string(ctx, -1, "\xff""\xff""zbx_env"))
159 return duk_error(ctx, DUK_RET_TYPE_ERROR, "cannot access internal environment");
160
161 env = (zbx_es_env_t *)duk_to_pointer(ctx, -1);
162 duk_pop(ctx);
163
164 duk_push_this(ctx);
165
166 request = (zbx_es_httprequest_t *)zbx_malloc(NULL, sizeof(zbx_es_httprequest_t));
167 memset(request, 0, sizeof(zbx_es_httprequest_t));
168
169 if (NULL == (request->handle = curl_easy_init()))
170 {
171 err_index = duk_push_error_object(ctx, DUK_RET_EVAL_ERROR, "cannot initialize cURL library");
172 goto out;
173 }
174
175 ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_COOKIEFILE, "", err);
176 ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_FOLLOWLOCATION, 1L, err);
177 ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_WRITEFUNCTION, curl_write_cb, err);
178 ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_WRITEDATA, request, err);
179 ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_PRIVATE, request, err);
180 ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_SSL_VERIFYPEER, 0L, err);
181 ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_TIMEOUT, (long)env->timeout, err);
182 ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_SSL_VERIFYHOST, 0L, err);
183 ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_HEADERFUNCTION, curl_header_cb, err);
184 ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_HEADERDATA, request, err);
185 ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_INTERFACE, CONFIG_SOURCE_IP, err);
186
187 duk_push_pointer(ctx, request);
188 duk_put_prop_string(ctx, -2, "\xff""\xff""d");
189
190 duk_push_c_function(ctx, es_httprequest_dtor, 1);
191 duk_set_finalizer(ctx, -2);
192 out:
193 if (-1 != err_index)
194 {
195 if (NULL != request->handle)
196 curl_easy_cleanup(request->handle);
197 zbx_free(request);
198
199 return duk_throw(ctx);
200 }
201
202 return 0;
203 }
204
205 /******************************************************************************
206 * *
207 * Function: es_httprequest_add_header *
208 * *
209 * Purpose: CurlHttpRequest.SetHeader method *
210 * *
211 ******************************************************************************/
es_httprequest_add_header(duk_context * ctx)212 static duk_ret_t es_httprequest_add_header(duk_context *ctx)
213 {
214 zbx_es_httprequest_t *request;
215 CURLcode err;
216 char *utf8 = NULL;
217 int err_index = -1;
218
219 if (NULL == (request = es_httprequest(ctx)))
220 return duk_error(ctx, DUK_RET_EVAL_ERROR, "internal scripting error: null object");
221
222 if (SUCCEED != zbx_cesu8_to_utf8(duk_to_string(ctx, 0), &utf8))
223 {
224 err_index = duk_push_error_object(ctx, DUK_RET_TYPE_ERROR, "cannot convert header to utf8");
225 goto out;
226 }
227
228 request->headers = curl_slist_append(request->headers, utf8);
229 ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_HTTPHEADER, request->headers, err);
230 request->custom_header = 1;
231 out:
232 zbx_free(utf8);
233
234 if (-1 != err_index)
235 return duk_throw(ctx);
236
237 return 0;
238 }
239
240 /******************************************************************************
241 * *
242 * Function: es_httprequest_clear_header *
243 * *
244 * Purpose: CurlHttpRequest.ClearHeader method *
245 * *
246 ******************************************************************************/
es_httprequest_clear_header(duk_context * ctx)247 static duk_ret_t es_httprequest_clear_header(duk_context *ctx)
248 {
249 zbx_es_httprequest_t *request;
250
251 if (NULL == (request = es_httprequest(ctx)))
252 return duk_error(ctx, DUK_RET_EVAL_ERROR, "internal scripting error: null object");
253
254 curl_slist_free_all(request->headers);
255 request->headers = NULL;
256 request->custom_header = 0;
257
258 return 0;
259 }
260
261 /******************************************************************************
262 * *
263 * Function: es_httprequest_query *
264 * *
265 * Purpose: CurlHttpRequest HTTP request implementation *
266 * *
267 * Parameters: ctx - [IN] the scripting engine context *
268 * http_request - [IN] the HTTP request (GET, PUT, POST, DELETE) *
269 * *
270 ******************************************************************************/
es_httprequest_query(duk_context * ctx,const char * http_request)271 static duk_ret_t es_httprequest_query(duk_context *ctx, const char *http_request)
272 {
273 zbx_es_httprequest_t *request;
274 char *url = NULL, *contents = NULL;
275 CURLcode err;
276 int err_index = -1;
277
278 if (SUCCEED != zbx_cesu8_to_utf8(duk_to_string(ctx, 0), &url))
279 {
280 err_index = duk_push_error_object(ctx, DUK_RET_TYPE_ERROR, "cannot convert URL to utf8");
281 goto out;
282 }
283
284 if (0 == duk_is_null_or_undefined(ctx, 1))
285 {
286 if (SUCCEED != zbx_cesu8_to_utf8(duk_to_string(ctx, 1), &contents))
287 {
288 err_index = duk_push_error_object(ctx, DUK_RET_TYPE_ERROR,
289 "cannot convert request contents to utf8");
290 goto out;
291 }
292 }
293
294 if (NULL == (request = es_httprequest(ctx)))
295 {
296 err_index = duk_push_error_object(ctx, DUK_RET_EVAL_ERROR, "internal scripting error: null object");
297 goto out;
298 }
299
300 ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_URL, url, err);
301
302 if (0 == request->custom_header)
303 {
304 struct zbx_json_parse jp;
305
306 if (NULL != request->headers)
307 {
308 curl_slist_free_all(request->headers);
309 request->headers = NULL;
310 }
311
312 if (NULL != contents)
313 {
314 if (SUCCEED == zbx_json_open(contents, &jp))
315 request->headers = curl_slist_append(NULL, "Content-Type: application/json");
316 else
317 request->headers = curl_slist_append(NULL, "Content-Type: text/plain");
318 }
319 }
320
321 ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_HTTPHEADER, request->headers, err);
322 ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_CUSTOMREQUEST, http_request, err);
323 ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_POSTFIELDS, ZBX_NULL2EMPTY_STR(contents), err);
324
325 request->data_offset = 0;
326 request->headers_in_offset = 0;
327
328 if (CURLE_OK != (err = curl_easy_perform(request->handle)))
329 {
330 err_index = duk_push_error_object(ctx, DUK_RET_EVAL_ERROR, "cannot get URL: %s.",
331 curl_easy_strerror(err));
332 goto out;
333 }
334 out:
335 zbx_free(url);
336 zbx_free(contents);
337
338 if (-1 != err_index)
339 return duk_throw(ctx);
340
341 duk_push_string(ctx, request->data);
342
343 return 1;
344 }
345
346 /******************************************************************************
347 * *
348 * Function: es_httprequest_get *
349 * *
350 * Purpose: CurlHttpRequest.Get method *
351 * *
352 ******************************************************************************/
es_httprequest_get(duk_context * ctx)353 static duk_ret_t es_httprequest_get(duk_context *ctx)
354 {
355 return es_httprequest_query(ctx, "GET");
356 }
357
358 /******************************************************************************
359 * *
360 * Function: es_httprequest_put *
361 * *
362 * Purpose: CurlHttpRequest.Put method *
363 * *
364 ******************************************************************************/
es_httprequest_put(duk_context * ctx)365 static duk_ret_t es_httprequest_put(duk_context *ctx)
366 {
367 return es_httprequest_query(ctx, "PUT");
368 }
369
370 /******************************************************************************
371 * *
372 * Function: es_httprequest_post *
373 * *
374 * Purpose: CurlHttpRequest.Post method *
375 * *
376 ******************************************************************************/
es_httprequest_post(duk_context * ctx)377 static duk_ret_t es_httprequest_post(duk_context *ctx)
378 {
379 return es_httprequest_query(ctx, "POST");
380 }
381
382 /******************************************************************************
383 * *
384 * Function: es_httprequest_delete *
385 * *
386 * Purpose: CurlHttpRequest.Delete method *
387 * *
388 ******************************************************************************/
es_httprequest_delete(duk_context * ctx)389 static duk_ret_t es_httprequest_delete(duk_context *ctx)
390 {
391 return es_httprequest_query(ctx, "DELETE");
392 }
393
394 /******************************************************************************
395 * *
396 * Function: es_httprequest_set_proxy *
397 * *
398 * Purpose: CurlHttpRequest.SetProxy method *
399 * *
400 ******************************************************************************/
es_httprequest_set_proxy(duk_context * ctx)401 static duk_ret_t es_httprequest_set_proxy(duk_context *ctx)
402 {
403 zbx_es_httprequest_t *request;
404 CURLcode err;
405 int err_index = -1;
406
407 if (NULL == (request = es_httprequest(ctx)))
408 return duk_error(ctx, DUK_RET_EVAL_ERROR, "internal scripting error: null object");
409
410 ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_PROXY, duk_to_string(ctx, 0), err);
411 out:
412 if (-1 != err_index)
413 return duk_throw(ctx);
414
415 return 0;
416 }
417
418 /******************************************************************************
419 * *
420 * Function: es_httprequest_status *
421 * *
422 * Purpose: CurlHttpRequest.Status method *
423 * *
424 ******************************************************************************/
es_httprequest_status(duk_context * ctx)425 static duk_ret_t es_httprequest_status(duk_context *ctx)
426 {
427 zbx_es_httprequest_t *request;
428 long response_code;
429 CURLcode err;
430
431 if (NULL == (request = es_httprequest(ctx)))
432 return duk_error(ctx, DUK_RET_EVAL_ERROR, "internal scripting error: null object");
433
434 if (CURLE_OK != (err = curl_easy_getinfo(request->handle, CURLINFO_RESPONSE_CODE, &response_code)))
435 return duk_error(ctx, DUK_RET_EVAL_ERROR, "cannot obtain request status: %s", curl_easy_strerror(err));
436
437 duk_push_number(ctx, (duk_double_t)response_code);
438
439 return 1;
440 }
441
442 /******************************************************************************
443 * *
444 * Function: parse_header *
445 * *
446 * Purpose: retrieves value of a header *
447 * *
448 * Parameters: header - [IN] the http header to extract value from *
449 * value_out - [OUT] the value *
450 * *
451 ******************************************************************************/
parse_header(char * header,char ** value_out)452 static int parse_header(char *header, char **value_out)
453 {
454 char *value;
455
456 if (NULL == (value = strchr(header, ':')))
457 return FAIL;
458
459 *value++ = '\0';
460 while (' ' == *value || '\t' == *value)
461 value++;
462
463 *value_out = value;
464
465 return SUCCEED;
466 }
467
468 /******************************************************************************
469 * *
470 * Function: es_obj_put_http_header *
471 * *
472 * Purpose: puts http header <field>: <value> as object property/value *
473 * *
474 * Parameters: ctx - [IN] the duktape context *
475 * idx - [IN] the object index on duktape stack *
476 * header - [IN] the http header to parse and put *
477 * *
478 ******************************************************************************/
es_put_header(duk_context * ctx,int idx,char * header)479 static void es_put_header(duk_context *ctx, int idx, char *header)
480 {
481 char *value;
482
483 if (FAIL == parse_header(header, &value))
484 return;
485
486 duk_push_string(ctx, value);
487
488 /* duk_put_prop_string() throws error on failure, no need to check return code */
489 (void)duk_put_prop_string(ctx, idx, header);
490 }
491
492 /******************************************************************************
493 * *
494 * Function: get_headers_as_strings *
495 * *
496 * Purpose: retrieve headers from request in form of strings *
497 * *
498 * Parameters: ctx - [IN] the duktape context *
499 * request - [IN] the request to retrieve headers from *
500 * *
501 ******************************************************************************/
get_headers_as_strings(duk_context * ctx,zbx_es_httprequest_t * request)502 static duk_ret_t get_headers_as_strings(duk_context *ctx, zbx_es_httprequest_t *request)
503 {
504 char *ptr, *header;
505 duk_idx_t idx;
506
507 idx = duk_push_object(ctx);
508
509 if (0 == request->headers_in_offset)
510 return 1;
511
512 for (ptr = request->headers_in; NULL != (header = zbx_http_parse_header(&ptr)); )
513 {
514 es_put_header(ctx, idx, header);
515 zbx_free(header);
516 }
517
518 return 1;
519 }
520
521 typedef struct
522 {
523 char *name;
524 zbx_vector_str_t values;
525 }
526 zbx_cached_header_t;
527
cached_headers_free(zbx_cached_header_t * header)528 static void cached_headers_free(zbx_cached_header_t *header)
529 {
530 zbx_vector_str_clear_ext(&header->values, zbx_str_free);
531 zbx_vector_str_destroy(&header->values);
532 zbx_free(header->name);
533 zbx_free(header);
534 }
535
536 /******************************************************************************
537 * *
538 * Function: get_headers_as_arrays *
539 * *
540 * Purpose: retrieve headers from request in form of arrays *
541 * *
542 * Parameters: ctx - [IN] the duktape context *
543 * request - [IN] the request to retrieve headers from *
544 * *
545 ******************************************************************************/
get_headers_as_arrays(duk_context * ctx,zbx_es_httprequest_t * request)546 static duk_ret_t get_headers_as_arrays(duk_context *ctx, zbx_es_httprequest_t *request)
547 {
548 char *ptr, *header;
549 zbx_vector_ptr_t headers;
550 duk_idx_t idx;
551 int i, j;
552
553 zbx_vector_ptr_create(&headers);
554
555 idx = duk_push_object(ctx);
556
557 if (0 == request->headers_in_offset)
558 goto out;
559
560 for (ptr = request->headers_in; NULL != (header = zbx_http_parse_header(&ptr)); )
561 {
562 char *value;
563 zbx_cached_header_t *existing_header = NULL;
564
565 if (FAIL == parse_header(header, &value))
566 {
567 zbx_free(header);
568 continue;
569 }
570
571 for (j = 0; j < headers.values_num; j++)
572 {
573 zbx_cached_header_t *h = (zbx_cached_header_t*)headers.values[j];
574
575 if (0 == strcmp(header, h->name))
576 {
577 existing_header = h;
578 zbx_vector_str_append(&existing_header->values, zbx_strdup(NULL, value));
579 zbx_free(header);
580
581 break;
582 }
583 }
584
585 if (NULL == existing_header)
586 {
587 zbx_cached_header_t *cached_header;
588
589 cached_header = zbx_malloc(NULL, sizeof(zbx_cached_header_t));
590
591 cached_header->name = header;
592 zbx_vector_str_create(&cached_header->values);
593 zbx_vector_str_append(&cached_header->values, zbx_strdup(NULL, value));
594 zbx_vector_ptr_append(&headers, cached_header);
595 }
596 }
597
598 for (i = 0; i < headers.values_num; i++) {
599 zbx_cached_header_t *h = (zbx_cached_header_t*)headers.values[i];
600 duk_idx_t arr_idx;
601 int j;
602
603 arr_idx = duk_push_array(ctx);
604
605 for (j = 0; j < h->values.values_num; j++)
606 {
607 duk_push_string(ctx, h->values.values[j]);
608 duk_put_prop_index(ctx, arr_idx, (duk_uarridx_t)j);
609 }
610
611 (void)duk_put_prop_string(ctx, idx, h->name);
612 }
613
614 out:
615 zbx_vector_ptr_clear_ext(&headers, (zbx_mem_free_func_t)cached_headers_free);
616 zbx_vector_ptr_destroy(&headers);
617 return 1;
618 }
619
620 /******************************************************************************
621 * *
622 * Function: es_httprequest_get_headers *
623 * *
624 * Purpose: CurlHttpRequest.GetHeaders method *
625 * *
626 ******************************************************************************/
es_httprequest_get_headers(duk_context * ctx)627 static duk_ret_t es_httprequest_get_headers(duk_context *ctx)
628 {
629 zbx_es_httprequest_t *request;
630
631 if (NULL == (request = es_httprequest(ctx)))
632 return duk_error(ctx, DUK_RET_EVAL_ERROR, "internal scripting error: null object");
633
634 if (0 == duk_is_null_or_undefined(ctx, 0))
635 {
636 duk_bool_t as_array;
637
638 as_array = duk_to_boolean(ctx, 0);
639
640 if (0 != as_array)
641 return get_headers_as_arrays(ctx, request);
642 }
643
644 return get_headers_as_strings(ctx, request);
645 }
646
647 /******************************************************************************
648 * *
649 * Function: es_httprequest_set_httpauth *
650 * *
651 * Purpose: CurlHttpRequest.SetHttpAuth method *
652 * *
653 ******************************************************************************/
es_httprequest_set_httpauth(duk_context * ctx)654 static duk_ret_t es_httprequest_set_httpauth(duk_context *ctx)
655 {
656 zbx_es_httprequest_t *request;
657 char *username = NULL, *password = NULL;
658 int err_index = -1, mask;
659 CURLcode err;
660
661 if (NULL == (request = es_httprequest(ctx)))
662 return duk_error(ctx, DUK_RET_EVAL_ERROR, "internal scripting error: null object");
663
664 mask = duk_to_int32(ctx, 0);
665
666 if (0 != (mask & ~(ZBX_HTTPAUTH_BASIC | ZBX_HTTPAUTH_DIGEST | ZBX_HTTPAUTH_NEGOTIATE | ZBX_HTTPAUTH_NTLM)))
667 return duk_error(ctx, DUK_RET_EVAL_ERROR, "invalid HTTP authentication mask");
668
669 if (0 == duk_is_null_or_undefined(ctx, 1))
670 {
671 if (SUCCEED != zbx_cesu8_to_utf8(duk_to_string(ctx, 1), &username))
672 {
673 err_index = duk_push_error_object(ctx, DUK_RET_TYPE_ERROR, "cannot convert username to utf8");
674 goto out;
675 }
676 }
677
678 if (0 == duk_is_null_or_undefined(ctx, 2))
679 {
680 if (SUCCEED != zbx_cesu8_to_utf8(duk_to_string(ctx, 2), &password))
681 {
682 err_index = duk_push_error_object(ctx, DUK_RET_TYPE_ERROR, "cannot convert username to utf8");
683 goto out;
684 }
685 }
686
687 ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_HTTPAUTH, mask, err);
688
689 if (NULL != username)
690 ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_USERNAME, username, err);
691
692 if (NULL != password)
693 ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_PASSWORD, password, err);
694
695 out:
696 zbx_free(password);
697 zbx_free(username);
698
699 if (-1 != err_index)
700 return duk_throw(ctx);
701
702 return 0;
703 }
704
705 static const duk_function_list_entry curlhttprequest_methods[] = {
706 {"AddHeader", es_httprequest_add_header, 1},
707 {"ClearHeader", es_httprequest_clear_header, 0},
708 {"Get", es_httprequest_get, 2},
709 {"Put", es_httprequest_put, 2},
710 {"Post", es_httprequest_post, 2},
711 {"Delete", es_httprequest_delete, 2},
712 {"Status", es_httprequest_status, 0},
713 {"SetProxy", es_httprequest_set_proxy, 1},
714 {"GetHeaders", es_httprequest_get_headers, 1},
715 {"SetHttpAuth", es_httprequest_set_httpauth, 3},
716 {NULL, NULL, 0}
717 };
718
719 static const duk_function_list_entry httprequest_methods[] = {
720 {"addHeader", es_httprequest_add_header, 1},
721 {"clearHeader", es_httprequest_clear_header, 0},
722 {"get", es_httprequest_get, 2},
723 {"put", es_httprequest_put, 2},
724 {"post", es_httprequest_post, 2},
725 {"delete", es_httprequest_delete, 2},
726 {"getStatus", es_httprequest_status, 0},
727 {"setProxy", es_httprequest_set_proxy, 1},
728 {"getHeaders", es_httprequest_get_headers, 1},
729 {"setHttpAuth", es_httprequest_set_httpauth, 3},
730 {NULL, NULL, 0}
731 };
732
733 #else
734
es_httprequest_ctor(duk_context * ctx)735 static duk_ret_t es_httprequest_ctor(duk_context *ctx)
736 {
737 if (!duk_is_constructor_call(ctx))
738 return DUK_RET_EVAL_ERROR;
739
740 return duk_error(ctx, DUK_RET_EVAL_ERROR, "missing cURL library");
741 }
742
743 static const duk_function_list_entry httprequest_methods[] = {
744 {NULL, NULL, 0}
745 };
746
747 static const duk_function_list_entry *curlhttprequest_methods = httprequest_methods;
748 #endif
749
es_httprequest_create_prototype(duk_context * ctx,const char * obj_name,const duk_function_list_entry * methods)750 static int es_httprequest_create_prototype(duk_context *ctx, const char *obj_name,
751 const duk_function_list_entry *methods)
752 {
753 duk_push_c_function(ctx, es_httprequest_ctor, 0);
754 duk_push_object(ctx);
755
756 duk_put_function_list(ctx, -1, methods);
757
758 if (1 != duk_put_prop_string(ctx, -2, "prototype"))
759 return FAIL;
760
761 if (1 != duk_put_global_string(ctx, obj_name))
762 return FAIL;
763
764 return SUCCEED;
765 }
766
zbx_es_init_httprequest(zbx_es_t * es,char ** error)767 int zbx_es_init_httprequest(zbx_es_t *es, char **error)
768 {
769 if (0 != setjmp(es->env->loc))
770 {
771 *error = zbx_strdup(*error, es->env->error);
772 return FAIL;
773 }
774
775 if (FAIL == es_httprequest_create_prototype(es->env->ctx, "CurlHttpRequest", curlhttprequest_methods) ||
776 FAIL == es_httprequest_create_prototype(es->env->ctx, "HttpRequest", httprequest_methods))
777 {
778 *error = zbx_strdup(*error, duk_safe_to_string(es->env->ctx, -1));
779 duk_pop(es->env->ctx);
780 return FAIL;
781 }
782
783 #ifdef HAVE_LIBCURL
784 duk_push_number(es->env->ctx, ZBX_HTTPAUTH_NONE);
785 duk_put_global_string(es->env->ctx, "HTTPAUTH_NONE");
786 duk_push_number(es->env->ctx, ZBX_HTTPAUTH_BASIC);
787 duk_put_global_string(es->env->ctx, "HTTPAUTH_BASIC");
788 duk_push_number(es->env->ctx, ZBX_HTTPAUTH_DIGEST);
789 duk_put_global_string(es->env->ctx, "HTTPAUTH_DIGEST");
790 duk_push_number(es->env->ctx, ZBX_HTTPAUTH_NEGOTIATE);
791 duk_put_global_string(es->env->ctx, "HTTPAUTH_NEGOTIATE");
792 duk_push_number(es->env->ctx, ZBX_HTTPAUTH_NTLM);
793 duk_put_global_string(es->env->ctx, "HTTPAUTH_NTLM");
794 #endif
795
796 return SUCCEED;
797 }
798