/* ** 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 <https://www.gnu.org/licenses/>. **/ #include "httprequest.h" #include "embed.h" #include "zbxstr.h" #include "zbxjson.h" #include "zbxhttp.h" #include "duktape.h" #include "zbxalgo.h" #include "zbxcurl.h" #include "global.h" #ifdef HAVE_LIBCURL #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 <field>: <value> 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; }