/*
** Copyright (C) 2001-2025 Zabbix SIA
**
** This program is free software: you can redistribute it and/or modify it under the terms of
** the GNU Affero General Public License as published by the Free Software Foundation, version 3.
**
** This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
** without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
** See the GNU Affero General Public License for more details.
**
** You should have received a copy of the GNU Affero General Public License along with this program.
** If not, see .
**/
#include "httprequest.h"
#include "embed.h"
#include "duktape.h"
#ifdef HAVE_LIBCURL
#include "global.h"
#include "zbxtime.h"
#include "zbxjson.h"
#include "zbxstr.h"
#include "zbxhttp.h"
#include "zbxcurl.h"
#include "zbxalgo.h"
#define ZBX_HTTPAUTH_NONE CURLAUTH_NONE
#define ZBX_HTTPAUTH_BASIC CURLAUTH_BASIC
#define ZBX_HTTPAUTH_DIGEST CURLAUTH_DIGEST
#define ZBX_HTTPAUTH_NEGOTIATE CURLAUTH_NEGOTIATE
#define ZBX_HTTPAUTH_NTLM CURLAUTH_NTLM
typedef struct
{
CURL *handle;
struct curl_slist *headers;
char *data;
char *headers_in;
size_t data_alloc;
size_t data_offset;
size_t headers_in_alloc;
size_t headers_in_offset;
unsigned char custom_header;
size_t headers_sz;
}
zbx_es_httprequest_t;
/* ZBX_CURL_SETOPT() macro is a code snippet to make code shorter and facilitate resource deallocation */
/* in case of error. Be careful with using ZBX_CURL_SETOPT(), duk_push_error_object() and duk_error() */
/* in functions - it is easy to get memory leaks because duk_error() causes longjmp(). */
/* Note that the caller of ZBX_CURL_SETOPT() must define variable 'int err_index' and label 'out'. */
#define ZBX_CURL_SETOPT(ctx, handle, opt, value, err) \
do \
{ \
if (CURLE_OK != (err = curl_easy_setopt(handle, opt, value))) \
{ \
err_index = duk_push_error_object(ctx, DUK_RET_EVAL_ERROR, \
"cannot set cURL option " #opt ": %s.", curl_easy_strerror(err)); \
goto out; \
} \
} \
while(0)
static size_t curl_write_cb(void *ptr, size_t size, size_t nmemb, void *userdata)
{
size_t r_size = size * nmemb;
zbx_es_httprequest_t *request = (zbx_es_httprequest_t *)userdata;
zbx_str_memcpy_alloc(&request->data, &request->data_alloc, &request->data_offset, (const char *)ptr, r_size);
return r_size;
}
static size_t curl_header_cb(void *ptr, size_t size, size_t nmemb, void *userdata)
{
size_t r_size = size * nmemb;
zbx_es_httprequest_t *request = (zbx_es_httprequest_t *)userdata;
zbx_strncpy_alloc(&request->headers_in, &request->headers_in_alloc, &request->headers_in_offset, (const char *)ptr, r_size);
return r_size;
}
/******************************************************************************
* *
* Purpose: return backing C structure embedded in HttpRequest object *
* *
******************************************************************************/
static zbx_es_httprequest_t *es_httprequest(duk_context *ctx)
{
zbx_es_env_t *env;
zbx_es_httprequest_t *request;
void *objptr;
if (NULL == (env = zbx_es_get_env(ctx)))
{
(void)duk_push_error_object(ctx, DUK_RET_EVAL_ERROR, "cannot access internal environment");
return NULL;
}
duk_push_this(ctx);
objptr = duk_require_heapptr(ctx, -1);
duk_pop(ctx);
if (NULL == (request = (zbx_es_httprequest_t *)es_obj_get_data(env, objptr, ES_OBJ_HTTPREQUEST)))
(void)duk_push_error_object(ctx, DUK_RET_EVAL_ERROR, "cannot find native data attached to object");
return request;
}
void es_httprequest_free(void *data)
{
zbx_es_httprequest_t *request = (zbx_es_httprequest_t *)data;
if (NULL != request->headers)
curl_slist_free_all(request->headers);
if (NULL != request->handle)
curl_easy_cleanup(request->handle);
zbx_free(request->data);
zbx_free(request->headers_in);
zbx_free(request);
}
/******************************************************************************
* *
* Purpose: HttpRequest destructor *
* *
******************************************************************************/
static duk_ret_t es_httprequest_dtor(duk_context *ctx)
{
zbx_es_httprequest_t *request;
zbx_es_env_t *env;
if (NULL == (env = zbx_es_get_env(ctx)))
return duk_error(ctx, DUK_RET_TYPE_ERROR, "cannot access internal environment");
if (NULL != (request = (zbx_es_httprequest_t *)es_obj_detach_data(env, duk_require_heapptr(ctx, -1),
ES_OBJ_HTTPREQUEST)))
{
env->http_req_objects--;
es_httprequest_free(request);
}
return 0;
}
/******************************************************************************
* *
* Purpose: HttpRequest constructor *
* *
******************************************************************************/
static duk_ret_t es_httprequest_ctor(duk_context *ctx)
{
#define MAX_HTTPREQUEST_OBJECT_COUNT 10
zbx_es_httprequest_t *request;
CURLcode err;
zbx_es_env_t *env;
int err_index = -1;
void *objptr;
if (!duk_is_constructor_call(ctx))
return DUK_RET_TYPE_ERROR;
if (NULL == (env = zbx_es_get_env(ctx)))
return duk_error(ctx, DUK_RET_TYPE_ERROR, "cannot access internal environment");
if (MAX_HTTPREQUEST_OBJECT_COUNT == env->http_req_objects)
return duk_error(ctx, DUK_RET_EVAL_ERROR, "maximum count of HttpRequest objects was reached");
duk_push_this(ctx);
objptr = duk_require_heapptr(ctx, -1);
request = (zbx_es_httprequest_t *)zbx_malloc(NULL, sizeof(zbx_es_httprequest_t));
memset(request, 0, sizeof(zbx_es_httprequest_t));
es_obj_attach_data(env, objptr, request, ES_OBJ_HTTPREQUEST);
if (NULL == (request->handle = curl_easy_init()))
{
err_index = duk_push_error_object(ctx, DUK_RET_EVAL_ERROR, "cannot initialize cURL library");
goto out;
}
ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_COOKIEFILE, "", err);
ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_FOLLOWLOCATION, 1L, err);
ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_WRITEFUNCTION, curl_write_cb, err);
ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_WRITEDATA, request, err);
ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_PRIVATE, request, err);
ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_SSL_VERIFYPEER, 0L, err);
ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_SSL_VERIFYHOST, 0L, err);
ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_HEADERFUNCTION, curl_header_cb, err);
ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_HEADERDATA, request, err);
if (NULL != env->config_source_ip)
ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_INTERFACE, env->config_source_ip, err);
duk_push_c_function(ctx, es_httprequest_dtor, 1);
duk_set_finalizer(ctx, -2);
out:
if (-1 != err_index)
{
(void)es_obj_detach_data(env, objptr, ES_OBJ_HTTPREQUEST);
if (NULL != request->handle)
curl_easy_cleanup(request->handle);
zbx_free(request);
return duk_throw(ctx);
}
env->http_req_objects++;
return 0;
#undef MAX_HTTPREQUEST_OBJECT_COUNT
}
/******************************************************************************
* *
* Purpose: HttpRequest.SetHeader method *
* *
******************************************************************************/
static duk_ret_t es_httprequest_add_header(duk_context *ctx)
{
#define ZBX_ES_MAX_HEADERS_SIZE ZBX_KIBIBYTE * 128
zbx_es_httprequest_t *request;
CURLcode err;
char *utf8 = NULL;
int err_index = -1;
size_t header_sz;
if (SUCCEED != es_duktape_string_decode(duk_safe_to_string(ctx, 0), &utf8))
{
err_index = duk_push_error_object(ctx, DUK_RET_TYPE_ERROR, "cannot convert header to utf8");
goto out;
}
if (NULL == (request = es_httprequest(ctx)))
{
err_index = 0;
goto out;
}
header_sz = strlen(utf8);
if (ZBX_ES_MAX_HEADERS_SIZE < request->headers_sz + header_sz)
{
err_index = duk_push_error_object(ctx, DUK_RET_TYPE_ERROR, "headers exceeded maximum size of "
ZBX_FS_UI64 " bytes.", ZBX_ES_MAX_HEADERS_SIZE);
goto out;
}
request->headers = curl_slist_append(request->headers, utf8);
ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_HTTPHEADER, request->headers, err);
request->custom_header = 1;
request->headers_sz += header_sz + 1;
out:
zbx_free(utf8);
if (-1 != err_index)
return duk_throw(ctx);
return 0;
#undef ZBX_ES_MAX_HEADERS_SIZE
}
/******************************************************************************
* *
* Purpose: HttpRequest.ClearHeader method *
* *
******************************************************************************/
static duk_ret_t es_httprequest_clear_header(duk_context *ctx)
{
zbx_es_httprequest_t *request;
if (NULL == (request = es_httprequest(ctx)))
return duk_throw(ctx);
curl_slist_free_all(request->headers);
request->headers = NULL;
request->custom_header = 0;
request->headers_sz = 0;
return 0;
}
typedef enum
{
CONTENT_TYPE_UNKNOWN,
CONTENT_TYPE_APPLICATION_JSON,
CONTENT_TYPE_TEXT_PLAIN
}
zbx_es_content_type_t;
/******************************************************************************
* *
* Purpose: HttpRequest HTTP request implementation *
* *
* Parameters: ctx - [IN] the scripting engine context *
* http_request - [IN] the HTTP request (GET, PUT, POST, DELETE) *
* *
******************************************************************************/
static duk_ret_t es_httprequest_query(duk_context *ctx, const char *http_request)
{
zbx_es_httprequest_t *request;
char *url = NULL, *contents = NULL, *error = NULL;
CURLcode err;
int err_index = -1;
zbx_es_env_t *env;
zbx_uint64_t timeout_ms, elapsed_ms;
duk_size_t contents_len = 0;
zbx_es_content_type_t content_type = CONTENT_TYPE_UNKNOWN;
if (NULL == (env = zbx_es_get_env(ctx)))
return duk_error(ctx, DUK_RET_TYPE_ERROR, "cannot access internal environment");
elapsed_ms = zbx_get_duration_ms(&env->start_time);
timeout_ms = (zbx_uint64_t)env->timeout * 1000;
if (elapsed_ms >= timeout_ms)
{
err_index = duk_push_error_object(ctx, DUK_RET_EVAL_ERROR, "script execution timeout occurred");
goto out;
}
if (SUCCEED != es_duktape_string_decode(duk_safe_to_string(ctx, 0), &url))
{
err_index = duk_push_error_object(ctx, DUK_RET_TYPE_ERROR, "cannot convert URL to utf8");
goto out;
}
if (0 == duk_is_null_or_undefined(ctx, 1))
{
if (NULL == (contents = es_get_buffer_dyn(ctx, 1, &contents_len)))
{
err_index = duk_push_error_object(ctx, DUK_RET_TYPE_ERROR, "cannot obtain second parameter");
goto out;
}
if (DUK_TYPE_STRING == duk_get_type(ctx, 1))
{
struct zbx_json_parse jp;
if (SUCCEED == zbx_json_open(contents, &jp))
content_type = CONTENT_TYPE_APPLICATION_JSON;
else
content_type = CONTENT_TYPE_TEXT_PLAIN;
}
}
if (NULL == (request = es_httprequest(ctx)))
{
err_index = duk_get_top_index(ctx);
goto out;
}
ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_URL, url, err);
if (0 == request->custom_header)
{
if (NULL != request->headers)
{
curl_slist_free_all(request->headers);
request->headers = NULL;
request->headers_sz = 0;
}
/* the post parameter will be converted to string and have terminating zero */
/* unless it had buffer or object type */
switch (content_type)
{
case CONTENT_TYPE_APPLICATION_JSON:
request->headers = curl_slist_append(NULL, "Content-Type: application/json");
break;
case CONTENT_TYPE_TEXT_PLAIN:
request->headers = curl_slist_append(NULL, "Content-Type: text/plain");
break;
default:
break;
}
}
ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_HTTPHEADER, request->headers, err);
ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_CUSTOMREQUEST, http_request, err);
ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_TIMEOUT_MS, timeout_ms - elapsed_ms, err);
ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_POSTFIELDS, ZBX_NULL2EMPTY_STR(contents), err);
ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_POSTFIELDSIZE, (long)contents_len, err);
ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_ACCEPT_ENCODING, "", err);
if (SUCCEED != zbx_curl_setopt_https(request->handle, &error))
{
err_index = duk_push_error_object(ctx, DUK_RET_EVAL_ERROR, "%s", error);
goto out;
}
request->data_offset = 0;
request->headers_in_offset = 0;
if (CURLE_OK != (err = curl_easy_perform(request->handle)))
{
err_index = duk_push_error_object(ctx, DUK_RET_EVAL_ERROR, "cannot get URL: %s.",
curl_easy_strerror(err));
goto out;
}
if (NULL != request->data)
zbx_http_convert_to_utf8(request->handle, &request->data, &request->data_offset, &request->data_alloc);
out:
zbx_free(url);
zbx_free(contents);
zbx_free(error);
if (-1 != err_index)
return duk_throw(ctx);
/* request->data already contains valid utf-8 string, sto it can be pushed directly */
duk_push_lstring(ctx, request->data, request->data_offset);
return 1;
}
/******************************************************************************
* *
* Purpose: HttpRequest.Get method *
* *
******************************************************************************/
static duk_ret_t es_httprequest_get(duk_context *ctx)
{
return es_httprequest_query(ctx, "GET");
}
/******************************************************************************
* *
* Purpose: HttpRequest.Put method *
* *
******************************************************************************/
static duk_ret_t es_httprequest_put(duk_context *ctx)
{
return es_httprequest_query(ctx, "PUT");
}
/******************************************************************************
* *
* Purpose: HttpRequest.Post method *
* *
******************************************************************************/
static duk_ret_t es_httprequest_post(duk_context *ctx)
{
return es_httprequest_query(ctx, "POST");
}
/******************************************************************************
* *
* Purpose: HttpRequest.Delete method *
* *
******************************************************************************/
static duk_ret_t es_httprequest_delete(duk_context *ctx)
{
return es_httprequest_query(ctx, "DELETE");
}
/******************************************************************************
* *
* Purpose: HttpRequest.head method *
* *
******************************************************************************/
static duk_ret_t es_httprequest_head(duk_context *ctx)
{
return es_httprequest_query(ctx, "HEAD");
}
/******************************************************************************
* *
* Purpose: HttpRequest.patch method *
* *
******************************************************************************/
static duk_ret_t es_httprequest_patch(duk_context *ctx)
{
return es_httprequest_query(ctx, "PATCH");
}
/******************************************************************************
* *
* Purpose: HttpRequest.options method *
* *
******************************************************************************/
static duk_ret_t es_httprequest_options(duk_context *ctx)
{
return es_httprequest_query(ctx, "OPTIONS");
}
/******************************************************************************
* *
* Purpose: HttpRequest.trace method *
* *
******************************************************************************/
static duk_ret_t es_httprequest_trace(duk_context *ctx)
{
return es_httprequest_query(ctx, "TRACE");
}
/******************************************************************************
* *
* Purpose: HttpRequest.connect method *
* *
******************************************************************************/
static duk_ret_t es_httprequest_connect(duk_context *ctx)
{
return es_httprequest_query(ctx, "CONNECT");
}
/******************************************************************************
* *
* Purpose: HttpRequest.customRequest method *
* *
******************************************************************************/
static duk_ret_t es_httprequest_customrequest(duk_context *ctx)
{
const char *method;
if (0 != duk_is_null_or_undefined(ctx, 0))
return duk_error(ctx, DUK_RET_EVAL_ERROR, "HTTP method cannot be undefined or null");
method = duk_safe_to_string(ctx, 0);
duk_remove(ctx, 0);
return es_httprequest_query(ctx, method);
}
/******************************************************************************
* *
* Purpose: HttpRequest.SetProxy method *
* *
******************************************************************************/
static duk_ret_t es_httprequest_set_proxy(duk_context *ctx)
{
zbx_es_httprequest_t *request;
CURLcode err;
int err_index = -1;
const char *proxy;
proxy = duk_safe_to_string(ctx, 0);
if (NULL == (request = es_httprequest(ctx)))
return duk_throw(ctx);
ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_PROXY, proxy, err);
out:
if (-1 != err_index)
return duk_throw(ctx);
return 0;
}
/******************************************************************************
* *
* Purpose: HttpRequest.Status method *
* *
******************************************************************************/
static duk_ret_t es_httprequest_status(duk_context *ctx)
{
zbx_es_httprequest_t *request;
long response_code;
CURLcode err;
if (NULL == (request = es_httprequest(ctx)))
return duk_throw(ctx);
if (CURLE_OK != (err = curl_easy_getinfo(request->handle, CURLINFO_RESPONSE_CODE, &response_code)))
return duk_error(ctx, DUK_RET_EVAL_ERROR, "cannot obtain request status: %s", curl_easy_strerror(err));
duk_push_number(ctx, (duk_double_t)response_code);
return 1;
}
/******************************************************************************
* *
* Purpose: retrieves value of a header *
* *
* Parameters: header - [IN] the http header to extract value from *
* value_out - [OUT] the value *
* *
******************************************************************************/
static int parse_header(char *header, char **value_out)
{
char *value;
if (NULL == (value = strchr(header, ':')))
return FAIL;
*value++ = '\0';
while (' ' == *value || '\t' == *value)
value++;
*value_out = value;
return SUCCEED;
}
/******************************************************************************
* *
* Purpose: puts http header : as object property/value *
* *
* Parameters: ctx - [IN] the duktape context *
* idx - [IN] the object index on duktape stack *
* header - [IN] the http header to parse and put *
* *
******************************************************************************/
static void es_put_header(duk_context *ctx, int idx, char *header)
{
char *value;
if (FAIL == parse_header(header, &value))
return;
es_push_result_string(ctx, value, strlen(value));
/* duk_put_prop_string() throws error on failure, no need to check return code */
(void)duk_put_prop_string(ctx, idx, header);
}
/******************************************************************************
* *
* Purpose: retrieve headers from request in form of strings *
* *
* Parameters: ctx - [IN] the duktape context *
* request - [IN] the request to retrieve headers from *
* *
******************************************************************************/
static duk_ret_t get_headers_as_strings(duk_context *ctx, zbx_es_httprequest_t *request)
{
char *ptr, *header;
duk_idx_t idx;
idx = duk_push_object(ctx);
if (0 == request->headers_in_offset)
return 1;
for (ptr = request->headers_in; NULL != (header = zbx_http_parse_header(&ptr)); )
{
es_put_header(ctx, idx, header);
zbx_free(header);
}
return 1;
}
typedef struct
{
char *name;
zbx_vector_str_t values;
}
zbx_cached_header_t;
static void cached_headers_free(zbx_cached_header_t *header)
{
zbx_vector_str_clear_ext(&header->values, zbx_str_free);
zbx_vector_str_destroy(&header->values);
zbx_free(header->name);
zbx_free(header);
}
/******************************************************************************
* *
* Purpose: retrieve headers from request in form of arrays *
* *
* Parameters: ctx - [IN] the duktape context *
* request - [IN] the request to retrieve headers from *
* *
******************************************************************************/
static duk_ret_t get_headers_as_arrays(duk_context *ctx, zbx_es_httprequest_t *request)
{
char *ptr, *header;
zbx_vector_ptr_t headers;
duk_idx_t idx;
int i, j;
zbx_vector_ptr_create(&headers);
idx = duk_push_object(ctx);
if (0 == request->headers_in_offset)
goto out;
for (ptr = request->headers_in; NULL != (header = zbx_http_parse_header(&ptr)); )
{
char *value;
zbx_cached_header_t *existing_header = NULL;
if (FAIL == parse_header(header, &value))
{
zbx_free(header);
continue;
}
for (j = 0; j < headers.values_num; j++)
{
zbx_cached_header_t *h = (zbx_cached_header_t*)headers.values[j];
if (0 == strcmp(header, h->name))
{
existing_header = h;
zbx_vector_str_append(&existing_header->values, zbx_strdup(NULL, value));
zbx_free(header);
break;
}
}
if (NULL == existing_header)
{
zbx_cached_header_t *cached_header;
cached_header = zbx_malloc(NULL, sizeof(zbx_cached_header_t));
cached_header->name = header;
zbx_vector_str_create(&cached_header->values);
zbx_vector_str_append(&cached_header->values, zbx_strdup(NULL, value));
zbx_vector_ptr_append(&headers, cached_header);
}
}
for (i = 0; i < headers.values_num; i++) {
zbx_cached_header_t *h = (zbx_cached_header_t*)headers.values[i];
duk_idx_t arr_idx;
arr_idx = duk_push_array(ctx);
for (j = 0; j < h->values.values_num; j++)
{
es_push_result_string(ctx, h->values.values[j], strlen(h->values.values[j]));
duk_put_prop_index(ctx, arr_idx, (duk_uarridx_t)j);
}
(void)duk_put_prop_string(ctx, idx, h->name);
}
out:
zbx_vector_ptr_clear_ext(&headers, (zbx_mem_free_func_t)cached_headers_free);
zbx_vector_ptr_destroy(&headers);
return 1;
}
/******************************************************************************
* *
* Purpose: HttpRequest.getHeaders method *
* *
******************************************************************************/
static duk_ret_t es_httprequest_get_headers(duk_context *ctx)
{
zbx_es_httprequest_t *request;
if (NULL == (request = es_httprequest(ctx)))
return duk_throw(ctx);
if (0 == duk_is_null_or_undefined(ctx, 0))
{
duk_bool_t as_array;
as_array = duk_to_boolean(ctx, 0);
if (0 != as_array)
return get_headers_as_arrays(ctx, request);
}
return get_headers_as_strings(ctx, request);
}
/******************************************************************************
* *
* Purpose: HttpRequest.SetHttpAuth method *
* *
******************************************************************************/
static duk_ret_t es_httprequest_set_httpauth(duk_context *ctx)
{
zbx_es_httprequest_t *request;
char *username = NULL, *password = NULL;
int err_index = -1, mask;
CURLcode err;
mask = duk_to_int32(ctx, 0);
if (0 != (mask & ~(ZBX_HTTPAUTH_BASIC | ZBX_HTTPAUTH_DIGEST | ZBX_HTTPAUTH_NEGOTIATE | ZBX_HTTPAUTH_NTLM)))
return duk_error(ctx, DUK_RET_EVAL_ERROR, "invalid HTTP authentication mask");
if (0 == duk_is_null_or_undefined(ctx, 1))
{
if (SUCCEED != es_duktape_string_decode(duk_safe_to_string(ctx, 1), &username))
{
err_index = duk_push_error_object(ctx, DUK_RET_TYPE_ERROR, "cannot convert username to utf8");
goto out;
}
}
if (0 == duk_is_null_or_undefined(ctx, 2))
{
if (SUCCEED != es_duktape_string_decode(duk_safe_to_string(ctx, 2), &password))
{
err_index = duk_push_error_object(ctx, DUK_RET_TYPE_ERROR, "cannot convert username to utf8");
goto out;
}
}
if (NULL == (request = es_httprequest(ctx)))
{
err_index = 0;
goto out;
}
ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_HTTPAUTH, mask, err);
if (NULL != username)
ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_USERNAME, username, err);
if (NULL != password)
ZBX_CURL_SETOPT(ctx, request->handle, CURLOPT_PASSWORD, password, err);
out:
zbx_free(password);
zbx_free(username);
if (-1 != err_index)
return duk_throw(ctx);
return 0;
}
static const duk_function_list_entry httprequest_methods[] = {
{"addHeader", es_httprequest_add_header, 1},
{"clearHeader", es_httprequest_clear_header, 0},
{"get", es_httprequest_get, 2},
{"put", es_httprequest_put, 2},
{"post", es_httprequest_post, 2},
{"delete", es_httprequest_delete, 2},
{"head", es_httprequest_head, 2},
{"patch", es_httprequest_patch, 2},
{"options", es_httprequest_options, 2},
{"trace", es_httprequest_trace, 2},
{"connect", es_httprequest_connect, 2},
{"getStatus", es_httprequest_status, 0},
{"setProxy", es_httprequest_set_proxy, 1},
{"getHeaders", es_httprequest_get_headers, 1},
{"setHttpAuth", es_httprequest_set_httpauth, 3},
{"customRequest", es_httprequest_customrequest, 3},
{NULL, NULL, 0}
};
#else
static duk_ret_t es_httprequest_ctor(duk_context *ctx)
{
if (!duk_is_constructor_call(ctx))
return DUK_RET_EVAL_ERROR;
return duk_error(ctx, DUK_RET_EVAL_ERROR, "missing cURL library");
}
static const duk_function_list_entry httprequest_methods[] = {
{NULL, NULL, 0}
};
#endif
static int es_httprequest_create_prototype(duk_context *ctx, const char *obj_name,
const duk_function_list_entry *methods)
{
duk_push_c_function(ctx, es_httprequest_ctor, 0);
duk_push_object(ctx);
duk_put_function_list(ctx, -1, methods);
if (1 != duk_put_prop_string(ctx, -2, "prototype"))
return FAIL;
if (1 != duk_put_global_string(ctx, obj_name))
return FAIL;
return SUCCEED;
}
int zbx_es_init_httprequest(zbx_es_t *es, char **error)
{
if (0 != setjmp(es->env->loc))
{
*error = zbx_strdup(*error, es->env->error);
return FAIL;
}
if (FAIL == es_httprequest_create_prototype(es->env->ctx, "HttpRequest", httprequest_methods))
{
*error = zbx_strdup(*error, duk_safe_to_string(es->env->ctx, -1));
duk_pop(es->env->ctx);
return FAIL;
}
#ifdef HAVE_LIBCURL
duk_push_number(es->env->ctx, ZBX_HTTPAUTH_NONE);
duk_put_global_string(es->env->ctx, "HTTPAUTH_NONE");
duk_push_number(es->env->ctx, ZBX_HTTPAUTH_BASIC);
duk_put_global_string(es->env->ctx, "HTTPAUTH_BASIC");
duk_push_number(es->env->ctx, ZBX_HTTPAUTH_DIGEST);
duk_put_global_string(es->env->ctx, "HTTPAUTH_DIGEST");
duk_push_number(es->env->ctx, ZBX_HTTPAUTH_NEGOTIATE);
duk_put_global_string(es->env->ctx, "HTTPAUTH_NEGOTIATE");
duk_push_number(es->env->ctx, ZBX_HTTPAUTH_NTLM);
duk_put_global_string(es->env->ctx, "HTTPAUTH_NTLM");
#endif
return SUCCEED;
}